Sé que esto va en contra de la idea de enumeraciones, pero ¿es posible extender las enumeraciones en C # / Java? Me refiero a "extender" en el sentido de agregar nuevos valores a una enumeración, pero también en el sentido de OO de heredar de una enumeración existente.
Supongo que no es posible en Java, ya que solo los obtuvo recientemente (¿Java 5?). Sin embargo, C # parece más indulgente con las personas que quieren hacer locuras, así que pensé que podría ser posible de alguna manera. Presumiblemente, podría ser pirateado a través de la reflexión (¿no es que todos usen ese método)?
No estoy necesariamente interesado en implementar un método dado, simplemente provocó mi curiosidad cuando se me ocurrió :-)
Respuestas:
La razón por la que no puede extender Enums es porque daría lugar a problemas de polimorfismo.
Digamos que tiene una enumeración MyEnum con valores A, B y C, y extiéndala con el valor D como MyExtEnum.
Supongamos que un método espera un valor myEnum en algún lugar, por ejemplo, como parámetro. Debería ser legal proporcionar un valor MyExtEnum, porque es un subtipo, pero ahora ¿qué va a hacer cuando resulte que el valor es D?
Para eliminar este problema, extender enumeraciones es ilegal
fuente
switch
valores de enumeración sin proporcionar undefault
caso o lanzar una excepción. E, incluso si lo hiciera, la enumeración en tiempo de ejecución podría provenir de una compilación separadadefault
caso o lanzamiento.switch
para proporcionar un valor requerido, como la inicial de un local, o toreturn
DayOfWeek a = (DayOfWeek) 1; DayOfWeek b = (DayOfWeek) 4711; Console.WriteLine(a + ", " + b);
Cuando las enumeraciones integradas no son suficientes, puede hacerlo a la antigua y crear las suyas propias. Por ejemplo, si desea agregar una propiedad adicional, por ejemplo, un campo de descripción, puede hacerlo de la siguiente manera:
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"); }
Luego puede tratarlo como una enumeración así:
public void ProcessAction(Action a) { Console.WriteLine("Performing action: " + a.Name) if (a == Action.DoIt) { // ... and so on } }
El truco consiste en asegurarse de que el constructor sea privado (o esté protegido si desea heredar) y que sus instancias sean estáticas.
fuente
final
a lapublic static Action DoIt = new Action("Do it", "This does things");
línea, en lugar de a la clase.readonly
, ala:public static readonly Action DoIt = new Action("Do it", "This does things");
Vas por el camino equivocado: una subclase de una enumeración tendría menos entradas.
En pseudocódigo, piense:
enum Animal { Mosquito, Dog, Cat }; enum Mammal : Animal { Dog, Cat }; // (not valid C#)
Cualquier método que pueda aceptar un Animal debería poder aceptar un Mamífero, pero no al revés. La subclasificación es para hacer algo más específico, no más general. Es por eso que "objeto" es la raíz de la jerarquía de clases. Del mismo modo, si las enumeraciones fueran heredables, entonces una raíz hipotética de la jerarquía de enumeraciones tendría todos los símbolos posibles.
Pero no, C # / Java no permite subenums, AFAICT, aunque a veces sería realmente útil. Probablemente sea porque eligieron implementar Enums como ints (como C) en lugar de símbolos internos (como Lisp). (Arriba, ¿qué representa (Animal) 1 y qué representa (Mammal) 1, y tienen el mismo valor?)
Sin embargo, podría escribir su propia clase enum (con un nombre diferente) que proporcione esto. Con los atributos de C #, incluso podría verse bastante bien.
fuente
Se supone que las enumeraciones representan la enumeración de todos los valores posibles, por lo que extender más bien va en contra de la idea.
Sin embargo, lo que puede hacer en Java (y presumiblemente C ++ 0x) es tener una interfaz en lugar de una clase de enumeración. Luego, coloque valores estándar en una enumeración que implemente la función. Obviamente, no puedes usar java.util.EnumSet y similares. Este es el enfoque adoptado en "más funciones NIO", que debería estar en JDK7.
public interface Result { String name(); String toString(); } public enum StandardResults implements Result { TRUE, FALSE } public enum WTFResults implements Result { FILE_NOT_FOUND }
fuente
Puede usar la reflexión .NET para recuperar las etiquetas y valores de una enumeración existente en tiempo de ejecución (
Enum.GetNames()
yEnum.GetValues()
son los dos métodos específicos que usaría) y luego usar la inyección de código para crear uno nuevo con esos elementos más algunos nuevos. Esto parece algo análogo a "heredar de una enumeración existente".fuente
Agregar enumeraciones es algo bastante común si regresa al código fuente y edita, cualquier otra forma (herencia o reflexión, si es posible) es probable que regrese y lo golpee cuando obtenga una actualización de la biblioteca y han introducido el mismo nombre de enumeración o el mismo valor de enumeración: he visto un montón de código de bajo nivel donde el número entero coincide con la codificación binaria, donde se encontrarían problemas
Idealmente, las enumeraciones de referencia de código deben escribirse solo como iguales (o conmutadores), y tratar de ser a prueba de futuro al no esperar que el conjunto de enumeraciones sea constante
fuente
Si te refieres a se extiende en el sentido de la clase Base, entonces en Java ... no.
Pero puede extender un valor de enumeración para tener propiedades y métodos si eso es lo que quiere decir.
Por ejemplo, lo siguiente usa una enumeración de soporte:
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; } }
fuente
No vi a nadie más mencionar esto, pero el valor ordinal de una enumeración es importante. Por ejemplo, con grails cuando guarda una enumeración en la base de datos, usa el valor ordinal. Si de alguna manera pudiera extender una enumeración, ¿cuáles serían los valores ordinales de sus extensiones? Si lo extendiera en varios lugares, ¿cómo podría conservar algún tipo de orden en estos ordinales? El caos / inestabilidad en los valores ordinales sería algo malo, lo que probablemente sea otra razón por la que los diseñadores del lenguaje no han tocado esto.
Otra dificultad si fueras el diseñador del lenguaje, ¿cómo puedes preservar la funcionalidad del método values () que se supone que devuelve todos los valores de enumeración? ¿En qué lo invocarías y cómo reuniría todos los valores?
fuente
Hace un tiempo vi una publicación sobre esto para Java, consulte http://www.javaspecialists.eu/archive/Issue161.html .
fuente
No puede heredar / extender una enumeración, puede usar atributos para declarar una descripción . Si está buscando un valor entero, está integrado.
fuente
Hmmm, hasta donde yo sé, esto no se puede hacer, las enumeraciones se escriben en tiempo de diseño y se utilizan para conveniencia del programador.
Estoy bastante seguro de que cuando se compile el código, los valores equivalentes serán sustituidos por los nombres en su enumeración, eliminando así el concepto de enumeración y (por lo tanto) la capacidad de extenderlo.
fuente
Me gustaría poder agregar valores a las enumeraciones de C # que son combinaciones de valores existentes. Por ejemplo (esto es lo que quiero hacer):
AnchorStyles se define como
public enum AnchorStyles { None = 0, Top = 1, Bottom = 2, Left = 4, Right = 8, }
y me gustaría agregar un AnchorStyles.BottomRight = Right + Bottom en lugar de decir
my_ctrl.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;
Solo puedo decir
my_ctrl.Anchor = AnchorStyles.BottomRight;
Esto no causa ninguno de los problemas que se han mencionado anteriormente, por lo que sería bueno si fuera posible.
fuente
Hace algún tiempo, incluso yo quería hacer algo como esto y descubrí que las extensiones de enumeración anularían muchos conceptos básicos ... (no solo polimorfismo)
Pero aún así, es posible que deba hacerlo si la enumeración se declara en una biblioteca externa y recuerde que debe tener una precaución especial al usar estas extensiones de enumeración ...
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; } }
fuente
En lo que respecta a Java, no está permitido porque agregar elementos a una enumeración crearía efectivamente una superclase en lugar de una subclase.
Considerar:
enum Person (JOHN SAM} enum Student extends Person {HARVEY ROSS}
Un caso de uso general de polimorfismo sería
Person person = Student.ROSS; //not legal
lo cual es claramente incorrecto.
fuente
Una solución temporal / local , cuando solo desea un uso muy 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 );
Vea todas las respuestas en: Enum "Herencia"
fuente