Melhor maneira de representar uma enumeração parametrizada em C#?
Pergunta
Existem boas soluções para representar um enum parametrizado em C# 3.0
?Estou procurando algo como OCaml ou Haxe tem.Só consigo pensar em hierarquia de classes com um campo enum simples para facilitar a troca por enquanto, talvez haja ideias melhores?
Veja o exemplo Ocaml abaixo em uma das respostas, segue um código Haxe:
enum Tree {
Node(left: Tree, right: Tree);
Leaf(val: Int);
}
Solução
Não estando familiarizado com OCaml ou Haxe, e não sendo inteligente o suficiente para entender as outras explicações, fui procurar o Documentação Haxe enum - o bit 'Enum Type Parameters' na parte inferior parece ser a parte relevante.
Meu entendimento com base nisso é o seguinte:
Um enum 'normal' é basicamente um valor restrito às coisas que você definiu em sua definição de enum.Exemplo C#:
enum Color{ Red, Green, Yellow, Blue };
Color c = Color.Red;
c
pode ser Red
, Green
, Yellow
, ou Blue
, mas nada mais.
No Haxe, você pode adicionar tipos complexos a enums, exemplo inventado de sua página:
enum Cell<T>{
empty;
cons( item : T, next : Cell<T> )
}
Cell<int> c = <I don't know>;
O que isso parece quer dizer é que c
está restrito a ser o valor literal empty
(como nossos antigos enums C#), ou também pode ser um tipo complexo cons(item, next)
, onde item
é um T
e next
é um Cell<T>
.
Como nunca usei isso, parece que provavelmente está gerando alguns tipos anônimos (como o compilador C# faz quando você faz new { Name='Joe'}
.
Sempre que você 'acessar' o valor enum, você deve declarar item
e next
quando você faz isso, parece que eles ficam vinculados a variáveis locais temporárias.
Exemplo Haxe - Você pode ver 'next' sendo usado como uma variável local temporária para extrair dados da estrutura anônima de cons:
switch( c ) {
case empty : 0;
case cons(item,next): 1 + cell_length(next);
}
Para ser honesto, isso me surpreendeu quando “cliquei” no que parecia estar fazendo.Parece incrivelmente poderoso e posso ver por que você estaria procurando um recurso semelhante em C#.
As enumerações C# são praticamente iguais às enumerações C/++ das quais foram originalmente copiadas.É basicamente uma maneira legal de dizer #define Red 1
para que o compilador possa fazer comparações e armazenamento com números inteiros em vez de strings quando você estiver passando Color
objetos ao redor.
Minha tentativa de fazer isso em C# seria usar genéricos e interfaces.Algo assim:
public interface ICell<T> {
T Item{ get; set; }
ICell<T>{ get; set; }
}
class Cons<T> : ICell<T> {
public T Item{ get; set; } /* C#3 auto-backed property */
public Cell<T> Next{ get; set; }
}
class EmptyCell<T> : ICell<T>{
public T Item{ get{ return default(T); set{ /* do nothing */ }; }
public ICell<T> Next{ get{ return null }; set{ /* do nothing */; }
}
Então você poderia ter um List<ICell<T>>
que conteria itens e a próxima célula, e você poderia inserir EmptyCell
no final (ou apenas tenha o Next
referência explicitamente definida como nula).As vantagens seriam porque EmptyCell
não contém variáveis de membro, não exigiria nenhum espaço de armazenamento (como o empty
em Haxe), enquanto um Cons
célula faria.
O compilador também pode incorporar/otimizar os métodos em EmptyCell
como eles não fazem nada, então pode haver um aumento de velocidade em relação a apenas ter um Cons
com seus dados de membro definidos como nulos.
Eu realmente não sei.Acolheria com agrado quaisquer outras soluções possíveis, pois não estou particularmente orgulhoso da minha :-)
Outras dicas
Use um aula isso com propriedades estáticas para representar os valores de enumeração.Você pode, opcionalmente, usar um construtor privado para forçar todas as referências à classe a passarem por uma propriedade estática.
Dê uma olhada no System.Drawing.Color
aula.Ele usa essa abordagem.
C# (o .NET framework em geral, até onde eu sei) não suporta enumerações parametrizadas como o Java.Dito isto, você pode querer dar uma olhada em Atributos.Alguns dos recursos que os enums Java são capazes podem ser realizados por meio de atributos.
O que há de errado em usar apenas uma classe para isso?É feio, mas foi assim que o pessoal de Java fez até ter suporte Enum integrado à linguagem!