Eu sei que isso vai contra a ideia de enums, mas é possível estender enums em C # / Java? Quero dizer "estender" no sentido de adicionar novos valores a um enum, mas também no sentido OO de herdar de um enum existente.
Suponho que não seja possível em Java, já que só os obteve recentemente (Java 5?). C # parece perdoar mais as pessoas que querem fazer coisas malucas, então eu pensei que poderia ser possível de alguma forma. Presumivelmente, ele poderia ser hackeado por meio de reflexão (não que você realmente usasse esse método).
Não estou necessariamente interessado em implementar qualquer método, apenas me despertou curiosidade quando me ocorreu :-)
Respostas:
A razão pela qual você não pode estender Enums é porque isso levaria a problemas com polimorfismo.
Digamos que você tenha um enum MyEnum com os valores A, B e C e o estenda com o valor D como MyExtEnum.
Suponha que um método espera um valor myEnum em algum lugar, por exemplo, como um parâmetro. Deve ser legal fornecer um valor MyExtEnum, porque é um subtipo, mas agora o que você vai fazer quando descobrir que o valor é D?
Para eliminar esse problema, estender enums é ilegal
fonte
switch
valores enum sem fornecer umdefault
caso ou lançar uma exceção. E, mesmo se viesse, o enum em tempo de execução poderia vir de uma compilação separadadefault
case ou jogando.switch
para fornecer um valor obrigatório, como a inicial de um local, ou parareturn
DayOfWeek a = (DayOfWeek) 1; DayOfWeek b = (DayOfWeek) 4711; Console.WriteLine(a + ", " + b);
Você está indo na direção errada: uma subclasse de um enum teria menos entradas.
Em pseudocódigo, pense:
enum Animal { Mosquito, Dog, Cat }; enum Mammal : Animal { Dog, Cat }; // (not valid C#)
Qualquer método que pode aceitar um Animal deve ser capaz de aceitar um Mamífero, mas não o contrário. A criação de subclasses é para tornar algo mais específico, não mais geral. É por isso que "objeto" é a raiz da hierarquia de classes. Da mesma forma, se enums fossem herdáveis, uma raiz hipotética da hierarquia de enum teria todos os símbolos possíveis.
Mas não, C # / Java não permite sub-enums, AFAICT, embora seja muito útil às vezes. Provavelmente é porque eles escolheram implementar Enums como ints (como C) em vez de símbolos internos (como Lisp). (Acima, o que (Animal) 1 representa e o que (Mamífero) 1 representa, e eles têm o mesmo valor?)
Você poderia escrever sua própria classe enum (com um nome diferente) que fornecesse isso, no entanto. Com atributos C #, pode até parecer legal.
fonte
Quando enums integrados não são suficientes, você pode fazer à moda antiga e criar o seu próprio. Por exemplo, se você quiser adicionar uma propriedade adicional, por exemplo, um campo de descrição, você pode fazer da seguinte maneira:
public class Action { public string Name {get; private set;} public string Description {get; private set;} private Action(string name, string description) { Name = name; Description = description; } public static Action DoIt = new Action("Do it", "This does things"); public static Action StopIt = new Action("Stop It", "This stops things"); }
Você pode então tratá-lo como um enum, assim:
public void ProcessAction(Action a) { Console.WriteLine("Performing action: " + a.Name) if (a == Action.DoIt) { // ... and so on } }
O truque é ter certeza de que o construtor é privado (ou protegido se você quiser herdar) e que suas instâncias são estáticas.
fonte
final
àpublic static Action DoIt = new Action("Do it", "This does things");
linha, ao invés da classe.readonly
, ala:public static readonly Action DoIt = new Action("Do it", "This does things");
Supõe-se que os enums representam a enumeração de todos os valores possíveis, portanto, estender, em vez disso, vai contra a ideia.
No entanto, o que você pode fazer em Java (e provavelmente C ++ 0x) é ter uma interface em vez de uma classe enum. Em seguida, coloque os valores padrão em um enum que implementa o recurso. Obviamente, você não pode usar java.util.EnumSet e similares. Esta é a abordagem adotada em "mais recursos NIO", que deveria estar no JDK7.
public interface Result { String name(); String toString(); } public enum StandardResults implements Result { TRUE, FALSE } public enum WTFResults implements Result { FILE_NOT_FOUND }
fonte
Você pode usar a reflexão do .NET para recuperar os rótulos e valores de um enum existente em tempo de execução (
Enum.GetNames()
eEnum.GetValues()
são os dois métodos específicos que você usaria) e, em seguida, usar injeção de código para criar um novo com esses elementos mais alguns novos. Isso parece um pouco análogo a "herdar de um enum existente".fonte
Adicionar enums é uma coisa bastante comum de se fazer se você voltar ao código-fonte e editar, qualquer outra forma (herança ou reflexão, se for possível) provavelmente voltará e baterá em você quando você fizer uma atualização da biblioteca e eles introduziram o mesmo nome de enum ou o mesmo valor de enum - tenho visto muitos códigos de baixo nível onde o número inteiro corresponde à codificação binária, onde você teria problemas
O ideal é que enums de referência de código devem ser escritos apenas como iguais (ou opções) e tente ser à prova de futuro, não esperando que o conjunto de enum seja const
fonte
Se você quer dizer extends no sentido de classe Base, então em Java ... não.
Mas você pode estender um valor enum para ter propriedades e métodos, se é isso que você quer dizer.
Por exemplo, o seguinte usa um enum Bracket:
class Person { enum Bracket { Low(0, 12000), Middle(12000, 60000), Upper(60000, 100000); private final int low; private final int high; Brackets(int low, int high) { this.low = low; this.high = high; } public int getLow() { return low; } public int getHigh() { return high; } public boolean isWithin(int value) { return value >= low && value <= high; } public String toString() { return "Bracket " + low + " to " + high; } } private Bracket bracket; private String name; public Person(String name, Bracket bracket) { this.bracket = bracket; this.name = name; } public String toString() { return name + " in " + bracket; } }
fonte
Não vi ninguém mencionar isso, mas o valor ordinal de um enum é importante. Por exemplo, com grails, quando você salva um enum no banco de dados, ele usa o valor ordinal. Se você pudesse de alguma forma estender um enum, quais seriam os valores ordinais de suas extensões? Se você o estendesse em vários lugares, como poderia preservar algum tipo de ordem para esses ordinais? Caos / instabilidade nos valores ordinais seria uma coisa ruim, o que provavelmente é outra razão pela qual os designers da linguagem não tocaram nisso.
Outra dificuldade, se você fosse o designer da linguagem, seria como preservar a funcionalidade do método values () que deve retornar todos os valores enum. Em que você invocaria isso e como reuniria todos os valores?
fonte
Vi uma postagem sobre isso para Java há algum tempo, verifique http://www.javaspecialists.eu/archive/Issue161.html .
fonte
Você não pode herdar / estender um enum, você pode usar atributos para declarar uma descrição . Se você está procurando um valor inteiro, ele está embutido.
fonte
Hmmm - pelo que eu sei, isso não pode ser feito - as enumerações são escritas em tempo de design e são usadas como uma conveniência para o programador.
Tenho certeza de que, quando o código for compilado, os valores equivalentes serão substituídos pelos nomes em sua enumeração, removendo assim o conceito de uma enumeração e (portanto) a capacidade de estendê-la.
fonte
Eu gostaria de poder adicionar valores às enumerações C # que são combinações de valores existentes. Por exemplo (isso é o que eu quero fazer):
AnchorStyles é definido como
public enum AnchorStyles { None = 0, Top = 1, Bottom = 2, Left = 4, Right = 8, }
e eu gostaria de adicionar AnchorStyles.BottomRight = Right + Bottom, em vez de dizer
my_ctrl.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;
Eu posso apenas dizer
my_ctrl.Anchor = AnchorStyles.BottomRight;
Isso não causa nenhum dos problemas mencionados acima, então seria bom se fosse possível.
fonte
Algum tempo atrás, até eu queria fazer algo assim e descobri que as extensões enum anulariam muitos conceitos básicos ... (não apenas polimorfise)
Mas você ainda pode precisar fazer se o enum for declarado em uma biblioteca externa e lembre-se de que você deve ter um cuidado especial ao usar essas extensões de enum ...
public enum MyEnum { A = 1, B = 2, C = 4 } public const MyEnum D = (MyEnum)(8); public const MyEnum E = (MyEnum)(16); func1{ MyEnum EnumValue = D; switch (EnumValue){ case D: break; case E: break; case MyEnum.A: break; case MyEnum.B: break; } }
fonte
No que diz respeito ao java, não é permitido porque adicionar elementos a um enum criaria efetivamente uma superclasse em vez de uma subclasse.
Considerar:
enum Person (JOHN SAM} enum Student extends Person {HARVEY ROSS}
Um caso de uso geral de polimorfismo seria
Person person = Student.ROSS; //not legal
o que está claramente errado.
fonte
Uma solução temporária / local , quando você deseja apenas um uso muito local / único:
enum Animals { Dog, Cat } enum AnimalsExt { Dog = Animals.Dog, Cat= Animals.Cat, MyOther} // BUT CAST THEM when using: var xyz = AnimalsExt.Cat; MethodThatNeedsAnimal( (Animals)xyz );
Veja todas as respostas em: Enum "Herança"
fonte