O que quero fazer é algo assim: tenho enums com valores sinalizados combinados.
public static class EnumExtension
{
public static bool IsSet<T>( this T input, T matchTo )
where T:enum //the constraint I want that doesn't exist in C#3
{
return (input & matchTo) != 0;
}
}
Então eu poderia fazer:
MyEnum tester = MyEnum.FlagA | MyEnum.FlagB
if( tester.IsSet( MyEnum.FlagA ) )
//act on flag a
Infelizmente, o C # é genérico em que as restrições não têm restrição de enum, apenas classe e estrutura. C # não vê enums como structs (embora sejam tipos de valor), portanto, não posso adicionar tipos de extensão como este.
Alguém conhece uma solução alternativa?
struct
apenas multa.Respostas:
EDITAR: Agora está disponível na versão 0.0.0.2 do UnconstrainedMelody.
(Conforme solicitado em minha postagem do blog sobre restrições de enum . Incluí os fatos básicos abaixo para obter uma resposta autônoma.)
A melhor solução é esperar que eu inclua no UnconstrainedMelody 1 . Esta é uma biblioteca que usa código C # com restrições "falsas", como
e o transforma em
por meio de uma etapa de postbuild.
Não deve ser muito difícil de escrever
IsSet
... embora atender às bandeiras baseadasInt64
eUInt64
baseadas em ambos possa ser a parte complicada. (Sinto o cheiro de alguns métodos auxiliares chegando, basicamente me permitindo tratar qualquer enum sinalizador como se ele tivesse um tipo base deUInt64
.)Qual você gostaria que fosse o comportamento se ligasse
? Ele deve verificar se todos os sinalizadores especificados estão definidos? Essa seria a minha expectativa.
Vou tentar fazer isso no caminho para casa esta noite ... Espero ter uma rápida blitz sobre métodos de enum úteis para colocar a biblioteca em um padrão utilizável rapidamente e, em seguida, relaxar um pouco.
EDIT: Não tenho certeza sobre
IsSet
como um nome, a propósito. Opções:Os pensamentos são bem-vindos. Tenho certeza de que vai demorar um pouco antes de qualquer coisa ser gravada em pedra de qualquer maneira ...
1 ou enviá-lo como um patch, é claro ...
fonte
colors.HasAny(Colors.Red | Colors.Blue)
parece um código muito legível.=)
where T : System.Enum
. Isso já foi escrito em outro lugar no tópico; apenas pensei em repetir aqui.A partir do C # 7.3, agora existe uma maneira integrada de adicionar restrições de enum:
fonte: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint
fonte
Darren, isso funcionaria se os tipos fossem enumerações específicas - para enumerações gerais funcionarem, você tem que convertê-las em ints (ou mais provavelmente uint) para fazer a matemática booleana:
fonte
Convert.ToUInt32
eu não encontrei em nenhum outro lugar. AFAIK, é a única solução Pre-Net-4 decente que também funciona em VB. BTW, se houvermatchTo
vários bits de sinalizador, substitua!= 0
por== Convert.ToUInt32(matchTo)
.Convert.ToUInt32
usado com um enum usará aConvert.ToUInt32(object)
sobrecarga, o que significa que o CLR primeiro encaixotará esses valores antes de passá-los para oToUInt32
método. Na maioria dos casos, isso não importa, mas é bom saber que você manterá o GC bastante ocupado se estiver usando algo assim para analisar milhões de enums por segundo.Na verdade, é possível, com um truque feio. No entanto, não pode ser usado para métodos de extensão.
Se desejar, você pode fornecer
Enums<Temp>
um construtor privado e uma classe herdada abstrata aninhada pública comTemp
asEnum
, para evitar versões herdadas de não enums.fonte
Você pode conseguir isso usando IL Weaving e ExtraConstraints
Permite que você escreva este código
O que é compilado
fonte
A partir do C # 7.3, você pode usar a restrição Enum em tipos genéricos:
Se quiser usar um enum Nullable, você deve deixar a restrição de estrutura organizacional:
fonte
Isso não responde à pergunta original, mas agora existe um método no .NET 4 chamado Enum.HasFlag que faz o que você está tentando fazer no seu exemplo
fonte
flag
. O .NET 4.0 já tem cinco anos.A maneira como faço isso é colocar uma restrição de estrutura e verificar se T é um enum em tempo de execução. Isso não elimina o problema completamente, mas o reduz um pouco
fonte
Usando seu código original, dentro do método, você também pode usar reflexão para testar se T é um enum:
fonte
Aqui está um código que acabei de criar que parece funcionar como você deseja, sem ter que fazer nada muito louco. Não está restrito apenas a enums definidos como Sinalizadores, mas sempre pode haver uma verificação inserida, se necessário.
fonte
se alguém precisa de IsSet genérico (criado imediatamente e pode ser melhorado), e / ou string para conversão onfly Enum (que usa EnumConstraint apresentado abaixo):
Se alguém ainda precisa do exemplo quente para criar a restrição de codificação Enum:
espero que isso ajude alguém.
fonte
Eu só queria adicionar Enum como uma restrição genérica.
Embora isso seja apenas para um pequeno método auxiliar, o uso
ExtraConstraints
é um pouco sobrecarregado para mim.Decidi apenas criar uma
struct
restrição e adicionar uma verificação de tempo de execução paraIsEnum
. Para converter uma variável de T em Enum, eu a lanço em objeto primeiro.fonte