c# java .net

c# - Extender una enumeración a través de la herencia



java .net (14)

Sé que esto va en contra de la idea de enumeraciones, pero ¿es posible extender 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 OO de heredar de una enumeración existente.

Supongo que no es posible en Java, ya que solo los obtuvo bastante recientemente (¿Java 5?). C # parece más indulgente con las personas que quieren hacer cosas locas, 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 cierto que realmente usarías ese método)?

No estoy necesariamente interesado en implementar ningún método dado, solo provocó mi curiosidad cuando se me ocurrió :-)


Agregar enumeraciones es una cosa bastante común que hacer si vuelve al código fuente y edita, de otra forma (la herencia o el reflejo, si es posible) es probable que regrese y le 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 con problemas

Idealmente, las enumeraciones de referencia de código deberían escribirse como iguales solamente (o conmutadores), y tratar de ser una prueba futura al no esperar que la enumeración sea const.


Cuando las enumeraciones incorporadas no son suficientes, puedes hacerlo a la vieja usanza y crear el tuyo propio. 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"); }

A continuación, 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 es asegurarse de que el constructor sea privado (o protegido si desea heredar) y que sus instancias son estáticas.


En lo que respecta a Java, no está permitido porque agregar elementos a una enumeración crearía de manera efectiva una súper clase en lugar de una subclase.

Considerar:

enum Person (JOHN SAM} enum Student extends First {HARVEY ROSS}

Un caso de uso general de polimorfismo sería

Person person = Student.ROSS; //not legal

lo cual es claramente incorrecto


Estás yendo por el camino equivocado: una subclase de una enumeración tendría menos entradas.

En pseudocódigo, piensa:

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. Subclases 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 enum tendría todos los símbolos posibles.

Pero no, C # / Java no permite sub-enums, 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 (Mamífero) 1, y tienen el mismo valor?)

Sin embargo, podría escribir su propia clase enum (con un nombre diferente) que proporcionara esto. Con los atributos de C #, incluso podría verse bien.


Hace algún tiempo incluso quería hacer algo así y descubrí que las extensiones de enum darían la vuelta a muchos conceptos básicos ... (no solo polimorfismo)

Pero aún puede necesitar hacer si la enumeración se declara en la biblioteca externa y Recuerde que debe tener una precaución especial al usar estas extensiones 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; } }



Hmmm - por lo que sé, esto no se puede hacer - las enumeraciones se escriben en el momento del diseño y se usan como una conveniencia para el programador.

Estoy bastante seguro de que cuando se compile el código, los valores equivalentes se sustituirán por los nombres en su enumeración, eliminando así el concepto de una enumeración y (por lo tanto) la capacidad de ampliarlo.


La razón por la que no puede extender los Enums es porque podría ocasionar problemas con el polimorfismo.

Supongamos que tiene un enum MyEnum con los valores A, B y C, y lo extiende con el valor D como MyExtEnum.

Supongamos que un método espera un valor myEnum en alguna parte, por ejemplo como un parámetro. Debería ser legal proporcionar un valor de MyExtEnum, porque es un subtipo, pero ahora, ¿qué vas a hacer cuando resulte que el valor es D?

Para eliminar este problema, extender enumeraciones es ilegal


Me gustaría poder agregar valores a las enumeraciones 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 así que en vez 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.



No vi a nadie más mencionar esto, pero el valor ordinal de una enumeración es importante. Por ejemplo, con griales cuando guarda una enumeración en la base de datos, utiliza el valor ordinal. Si de alguna manera podría extender una enumeración, ¿cuáles serían los valores ordinales de sus extensiones? Si lo extendió en varios lugares, ¿cómo podría preservar algún tipo de orden para estos ordinales? El caos / la inestabilidad en los valores ordinales sería una mala cosa, que probablemente sea otra razón por la cual los diseñadores de idiomas no han tocado esto.

Otra dificultad si fue el diseñador del lenguaje, ¿cómo puede preservar la funcionalidad del método values ​​() que se supone que devuelve todos los valores enum? ¿Cómo invocaría esto y cómo reuniría todos los valores?


Puede usar la reflexión .NET para recuperar las etiquetas y los valores de una enumeración existente en tiempo de Enum.GetNames() ( Enum.GetNames() y Enum.GetValues() son los dos métodos específicos que usaría) y luego use la inyección de código para crear una nueva uno con esos elementos más algunos nuevos. Esto parece análogo a "heredar de una enumeración existente".


Se supone que los enums representan la enumeración de todos los valores posibles, por lo que extenderlos 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 enum. Luego, ponga 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 características de 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 }


Si quiere decir extiende en el sentido de clase Base, entonces en Java ... no.

Pero puedes extender un valor enum para tener propiedades y métodos si eso es lo que quieres decir.

Por ejemplo, lo siguiente usa una enumeración de paréntesis:

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; } }