Pregunta

Tengo un problema con la enumeración

Necesito hacer una enumeración en la clase base o interfaz (pero vacía)

class Base 
{
   public enum Test;
   // ???
}

y después de hacer enumeraciones diferentes en algunas clases primarias

class Parent1
{
   public enum Test {A, B, C};
}

class Parent2
{
   public enum Test {J, H, K};
}

y ahora tengo la próxima clase con método cuando tengo que usar enum

class Test<T>
{
   public void Foo(Test enum)
   {
      int value = (int) enum;
      // ...
   }
}

¿Hay alguna forma de hacer algo así?

Si no, tengo que usar entradas estáticas en cada clase ...

class Parent1
{
   public static int A = 0;
   public static int B = 5;
   public static int C = 7;
}

class Parent2
{
   public static int J = 1;
   public static int H = 3;
   public static int K = 6;
}

class Test<T>
{
   public void Foo(int enum)
   {
      int value = enum;
      // ...
   }
}

No se ve mal en el código ... en algunas clases tengo que usar ~ 20 + variables

¿Fue útil?

Solución

No existe una enumeración abstracta (que puede tener implementaciones diferentes en subclases), pero los genéricos pueden ser una opción:

class Base<T> where T : struct {
    private T value;
    public void Foo(T value) {
        this.value = value;
    }
}
class Parent1 : Base<Parent1.Enum1> {
    public enum Enum1 {A, B, C};
}
class Parent2 : Base<Parent2.Enum2> {
    public enum Enum2 { J, H, K };
}

El único problema es que esto no exige que solo las enumeraciones sean utilizables; sin embargo, puede hacerlo en tiempo de ejecución; por ejemplo, en un inicializador de tipo:

static Base() {
    if (!typeof(T).IsEnum) throw new InvalidOperationException(
         typeof(T).Name + " is not an enum");
}

Otros consejos

Es sorprendente la frecuencia con la que encuentro personas discutiendo sobre por qué se requiere algo, en lugar de responder la pregunta que se hace o mantener el schtum, lo que sería más útil que perder el tiempo cuestionando por qué una consulta dada se ha realizado con preferencia a una consulta diferente a la que el encuestado realmente sabe la respuesta. Responder preguntas que no se han hecho no es de ninguna manera útil, ¿está bien chicos?

Volviendo al tema en cuestión, he tocado exactamente el escenario anterior esta mañana, y puedo entender por qué sería útil poder definir una enumeración en una interfaz o clase base, luego redefinir eso mismo -nombre Enum en una clase que deriva de la base o la interfaz. Un uso para tal diseño es el mapeo relacional de objetos y el enlace de control. Es posible que tenga un conjunto de enumeraciones que describan qué propiedades de sus clases derivadas se pueden vincular a qué tipos de control, como:

    public enum WebControlTextBoxProperties { }

    public enum WebControlLabelProperties { }

... y así sucesivamente.

Dado que no sabe exactamente qué Propiedades existirán para una clase derivada dada hasta que la herencia pertinente entre en vigencia, pero dado que también puede desear tener Métodos consistentes que consuman las Enums anteriores en su base o interfaz, es perfectamente diseño válido para esperar poder definir que el Enum existirá en la base / interfaz, pero defina exactamente qué miembros tiene en un contexto específico en cualquier clase derivada .

Realmente desearía que esto fuera posible en C # como lo es en VB, porque sería una característica realmente útil.

Debería poder declarar una enumeración en una clase base y luego cambiar los valores por clase derivada, es decir,

class MyClass
{
    public enum TestEnum { }

    public MyClass()
    {
    }
}

class MyDerivedClass
{
    public enum TestEnum { value1, value2, value3 }

    public MyDerivedClass()
    {
    }
}

La clase MyDervied tendría acceso a TestEnum.value1, TestEnum.value2, TestEnum.value3, donde MyClass solo tendría acceso al tipo.

Sin embargo, personalmente no veo la ventaja de hacer esto, declararía TODOS los valores de la enumeración en la clase base y solo usaría los que necesito por clase.

James.

No, no se puede hacer.

Tenga en cuenta que muchas enumeraciones a menudo indican un problema con el diseño (muchas construcciones de conmutadores, por ejemplo). Consulte este enlace para ver un ejemplo de cómo refactorizar esto: Reemplace condicional por polimorfismo .

No, no hay forma de aplicar nada estático en una interfaz.

Quizás necesite repensar su diseño.

¿Por qué no puedes definir la enumeración en la clase base:

class Base 
{
   public enum Test {A, B, C, J, H, K};
}

¿Y usa solo los miembros relevantes de enum en clases derivadas?

Estoy en el trabajo, así que no puedo dar más detalles, pero esto es posible hasta cierto punto. La desventaja del siguiente código es que no puede encadenar enumeraciones, como TextBoxProperties y MyCustomTextBoxProperties: TextboxProperties

Aquí está el código.

    public enum Test
    {

    }

    public enum ThisTest
    {
        MyVal1,
        MyVal2,
        MyVal3
    }

    public abstract class MyBase
    {
        public Test MyEnum { get; set; }
    }

    public class MyDerived : MyBase
    {
        public new ThisTest MyEnum { get; set; }
    }

¡USTED PUEDE RESUMIR UN ENUM!

¿Por qué la gente insiste en afirmar que las cosas son imposibles sin verificar nada?

Claro, la documentación de .NET es un poco vaga en esto, pero la clase System.Enum, ES la abstracción de una enumeración. Puede usar System.Enum como una variable que SOLO aceptará valores de enumeración, y puede acceder al nombre o valor de tipo de valor de la enumeración a través de esta clase.

Por ejemplo:

        // abstracted enumeration value
        Enum abstractEnum = null;

        // set to the Console-Color enumeration value "Blue";
        abstractEnum = System.ConsoleColor.Blue;

        // the defined value of "ConsoleColor.Blue" is "9":
        // you can get the value via the ToObject method:
        Console.WriteLine((int)Enum.ToObject(abstractEnum.GetType(), abstractEnum));

        // or via the GetHashCode() method:
        Console.WriteLine(abstractEnum.GetHashCode());

        // the name can also be acessed:
        Console.WriteLine(Enum.GetName(abstractEnum.GetType(), abstractEnum));

La salida del código anterior:

9

9

Azul

Me gusta la respuesta aceptada de @Marc Gravell. Como soy un novato de stackoverflow, no puedo comentar. Pero me gustaría agregar que es útil verificar también el Tipo subyacente de la enumeración, especialmente si usa el Atributo de marca y las operaciones de Prueba de marca de bit en forma de preforma ...

if ( !typeof(T).IsEnum || typeof(int) != Enum.GetUnderlyingType(typeof(T)) )
{
     throw new InvalidOperationException( typeof(T).Name + " is not an enum");
}

Aquí hay una solución que funciona para mí:

en la clase padre, declare el campo como int, no como enumeración:

protected int state;

para que la clase padre todavía pueda usar este valor como int, para proporcionar serialización y deserialización de este valor al disco.

Entonces, quién anula la clase puede hacer esto:

enum states{
  state1, state2
}

this.state = state1.toInt();

y puede acceder al valor real de esta manera:

...
if (this.state == states.state1.toInt()){
      ...
}
else{
     ...
}

donde toInt () se define en una clase estática de la siguiente manera:

public static class Utils
{

    public static int toInt(this state s)
    {
        return (int)s;
    }
 }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top