2009-06-23 31 views
12

tengo un problema en esta enumeraciónC# enum en la interfaz/clase base?

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 diffrent en algunas clases padre

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

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

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

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

¿Hay alguna manera de hacer algo como eso?

Si no tengo que usar enteros 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; 
     // ... 
    } 
} 

I't se ve mal en el código ... en algunas clases tengo que usar ~ 20 + variables de

+2

Quizás sería una buena idea volver a verificar sus suposiciones, ¿por qué lo necesitaría? Intenta reformular la pregunta para incluir lo que realmente intentas hacer, en lugar de enfocarte en la forma en que te estás acercando al problema. :) – Rytmis

+0

¿Para qué es lo que realmente quieres usar? Tener implementaciones diferentes de la misma enumeración parece ser lo opuesto a lo que una enumeración pretende ... – Guffa

+3

@Groo: no, eso es agregar valores a una enumeración, esto es tener una enumeración abstracta que tiene valores específicos de objeto, pero implementa una interfaz coherente, por lo que sus miembros se pueden pasar. La respuesta de Marc es la mejor que he visto. –

Respuesta

25

No hay tal cosa como una enumeración abstracta (que puede tener diferentes implementaciones en las subclases) - pero los genéricos puede 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 hace cumplir que sólo enumeraciones son utilizables - usted puede hacer esto en tiempo de ejecución, aunque - por ejemplo en un inicializador de tipo:

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

así su mejor solución posible, no puedo usar una sola cosa: abstracta DB clase pública donde T: Base , interf, nuevo() entiendo por qué, tengo que utilizar static int no de enumeraciones luego – kaem

+0

"There no es algo así como una enumeración abstracta (que puede tener diferentes implementaciones en subclases), pero los genéricos pueden ser una opción: "- ¡¡¡INCORRECTO !!! System.Enum es la base abstracta de todas las enumeraciones –

+0

@SimonBridge, consulte el contexto de la pregunta –

0

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

Quizás deba replantear su diseño.

0

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

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

Y use solo los miembros relevantes de enum en las clases derivadas?

+0

debido al principio "abrir para la extensión cerrada por modificación". No queremos cambiar la clase base cuando necesitamos un nuevo valor en la clase derivada. En cambio, queremos extender la enumeración de la clase base con nuevos valores en las clases derivadas. – ferit

1

No, no se puede hacer.

Tenga en cuenta que muchas enumeraciones a menudo indican un problema con el diseño (muchas construcciones de conmutación, por ejemplo). Consulte este enlace para ver un ejemplo de cómo refactorizar esto: Replace conditional with polymorphism.

3

Usted debe ser capaz de 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() 
    { 
    } 
} 

clase MyDervied tendrían acceso a TestEnum.value1, TestEnum.value2, TestEnum.value3, donde como 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é los que necesito por clase.

James.

+2

El problema es que yo no creo clases secundarias, sino algunos usuarios, y no quiero que modifiquen los valores de suma de la clase principal a esta enumeración – kaem

+0

hmmm y tengo un conflicto si uso esta solución, pero es posible hacer eso: nueva enumeración pública TestEnum {value1, value2, value3} hmmmm – kaem

+0

Sí, cuanto más pienso sobre lo que intentas hacer, no es posible. Al declarar nueva enumeración pública, TestEnum creará un tipo de enum separado para la clase base. Creo que la solución correcta sería tener una enumeración en la clase base solamente. – James

27

Es sorprendente la frecuencia me encuentro con personas que discuten sobre qué algo que se requiere, en lugar de responder a la pregunta planteada o mantener schtum - cualquiera de los cuales podría ser más útil que perder el tiempo cuestionando por qué se ha hecho una investigación dada en lugar de una consulta diferente, el encuestado conoce la respuesta. Responder las preguntas que no se han formulado no es de ninguna manera útil, ¿vale chicos?

Volviendo al tema en cuestión, he acertado exactamente con el escenario anterior esta mañana, y puedo entender por qué sería útil poder definir un Enum en una interfaz o clase base, luego redefinir eso el mismo nombre Enum en una clase que se deriva de la base o la interfaz. Un uso para dicho diseño es el mapeo relacional de objetos y el enlace de control. Es posible que tenga un conjunto de enumeraciones que describen las propiedades de sus clases derivadas son enlazable a qué tipos de control, tales 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 surta efecto, pero dado que también puede desear tener Métodos consistentes que consuman los Enums anteriores en su base o interfaz, es diseño perfectamente válido para esperar poder definir que Enum existirá en la base/interfaz, pero defina exactamente qué miembros tiene en un contexto específico en cualquier clase derivada.

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

+2

Para mí, preguntar por qué se rehúsa algo es una forma de pedir más información. Muy a menudo la respuesta de la pregunta es "Esto no es posible". pero al descubrir por qué se necesita una solución puede proporcionar opciones o instrucciones adicionales. – Trisped

+0

Tripeado, seguro, pero pocos salen y dicen "maldición, el lenguaje X no puede hacer eso, aquí hay una alternativa cercana"."En cambio, transfieren la culpa a las intenciones del programador, lo que sugiere que el programador violó una doctrina perfecta creada por los diseñadores del lenguaje. Eso no tiene sentido. Sin relación, usted escribió el mejor párrafo de 2010 Rachel. – erisco

0

Estoy trabajando así que no puedo dar más detalles, pero esto es posible hasta cierto punto. La desventaja del código siguiente es que no puede encadenar enumeraciones juntas, 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; } 
    } 
0

YOU CAN RESUMEN una enumeración!

¿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 SOLAMENTE aceptará valores de enumeración, y puede acceder al nombre o valor 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:

azul

+2

Esta es una muy mala idea. no es un 'enum'. Cada vez que use' Enum' como campo/tipo de variable (por ejemplo 'Enum abstractEnum') está agregando boxeo, completamente innecesario. Es engañoso afirmar que' Enum' es la abstracción de un 'enum', de la misma manera que es engañoso afirmar que' object' es la abstracción de una 'struct'. El tiempo de ejecución es capaz de * tratarlo así, pero a un costo no trivial –

+1

Just ' porque algo es un poco ineficiente no significa que esté mal, además, no dije que era una buena idea, solo dije que funciona. –

+1

Definir 'no trivial' de todos modos ... ¿está llamando a una operación de boxeo 'no trivial 'en el contexto de una .NE. ¿Aplicación T? Si le preocupa el impacto en el rendimiento de las operaciones de boxeo en un valor de enumeración, entonces debe usar un lenguaje de programación no administrado como C++, me temo que .NET simplemente no es lo suficientemente rápido como para notar la diferencia, es después de todo, un tiempo de ejecución administrado, NO un sistema en tiempo real. –

0

me gusta la respuesta aceptada de @Marc Gravell. Como soy un stackoverflow-novato, no tengo permitido comentar.Pero me gustaría añadir, que es útil para comprobar también la subyacente tipo de la enumeración - especialmente si utiliza las operaciones de bandera-Prueba de indicador de atributo y la preforma bit a bit ...

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

he aquí una solución que funciona para mí:

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

protected int state; 

por lo que la clase padre todavía se puede utilizar este valor como un entero, a fin de proporcionar la serialización y deserializion de este valor al disco.

Entonces, que anula la clase puede hacer esto:

enum states{ 
    state1, state2 
} 

this.state = state1.toInt(); 

y se puede acceder al valor real de la siguiente 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; 
    } 
}