Domanda

ho un problema con enum

Ho bisogno di creare un enum nella classe base o nell'interfaccia (ma vuota)

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

e in seguito fanno enumerazioni diverse in alcune classi genitore

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

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

e ora ho la prossima lezione con il metodo quando devo usare enum

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

Esiste un modo per fare qualcosa del genere?

In caso contrario, devo usare ints statici in ogni classe ...

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

Non sto male nel codice ... in alcune classi devo usare ~ 20 + variabili

È stato utile?

Soluzione

Non esiste un enum astratto (che può avere implementazioni diverse nelle sottoclassi) - ma i generici possono essere un'opzione:

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

L'unico problema è che ciò non impone che siano utilizzabili solo enumerazioni, tuttavia è possibile farlo in fase di esecuzione, ad esempio in un inizializzatore di tipo:

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

Altri suggerimenti

È sorprendente la frequenza con cui trovo persone che discutono di perché è necessario qualcosa, piuttosto che rispondere alla domanda posta o mantenere schtum - uno dei due sarebbe più utile che perdere tempo a interrogare perché è stata effettuata una determinata richiesta preferibilmente a un'altra richiesta a cui il rispondente conosce effettivamente la risposta. Rispondere a domande che non sono state poste non è in alcun modo utile, ok ragazzi ?!

Tornando all'argomento in questione, stamattina ho toccato esattamente lo scenario sopra e posso capire perché sarebbe utile poter definire un Enum in un'interfaccia o in una classe base, quindi ridefinire lo stesso -enominato Enum in una classe che deriva dalla base o dall'interfaccia. Un uso per tale progettazione è nella mappatura relazionale ad oggetti e nell'associazione di controllo. Potresti avere un set di Enum che descrivono quali Proprietà delle tue classi derivate sono associabili a quali tipi di Controllo, come:

    public enum WebControlTextBoxProperties { }

    public enum WebControlLabelProperties { }

... e così via.

Dal momento che non sai esattamente quali Proprietà esisteranno per una data classe derivata fino a quando l'ereditarietà pertinente avrà effetto, ma poiché potresti anche voler avere Metodi coerenti che consumino gli Enum sopra nella tua base o interfaccia, è perfettamente -valido design che prevede di essere in grado di definire che l'Enum esisterà nella base / interfaccia, ma definisce esattamente quali membri ha in un contesto specifico in qualsiasi classe derivata .

Vorrei davvero che ciò fosse possibile in C # come in VB, perché sarebbe una funzionalità davvero utile.

Dovresti essere in grado di dichiarare un'enum in una classe base e quindi modificare i valori per classe derivata, ad es.

class MyClass
{
    public enum TestEnum { }

    public MyClass()
    {
    }
}

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

    public MyDerivedClass()
    {
    }
}

La classe MyDervied avrebbe accesso a TestEnum.value1, TestEnum.value2, TestEnum.value3, dove come MyClass avrebbe accesso solo al tipo.

Tuttavia, personalmente non vedo il vantaggio di farlo, dichiarerei TUTTI i valori dell'enum nella classe base e userò solo quelli di cui ho bisogno per classe.

James.

No, non può essere fatto.

Nota che molti enum spesso indicano un problema con il design (molti costrutti di switch, per esempio). Controlla questo link per vedere un esempio di come eseguire il refactoring di questo: Sostituisci condizionale con polimorfismo .

No, non c'è modo di imporre nulla di statico in un'interfaccia.

Forse devi ripensare il tuo design.

Perché non riesci a definire l'enum nella classe base:

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

E usare solo i membri rilevanti di enum nelle classi derivate?

Sono al lavoro, quindi non posso elaborarlo completamente, ma questo è possibile fino a un certo punto. Il rovescio della medaglia del codice seguente è che non è possibile concatenare gli enum, come TextBoxProperties e MyCustomTextBoxProperties: TextboxProperties

Ecco il codice.

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

TU PUOI ESTRARRE UN ENUM!

Perché le persone insistono nel sostenere che le cose sono impossibili senza controllare nulla?

Certo, la documentazione di .NET è un po 'vaga su questo, ma la classe System.Enum, È l'astrazione di un enum. Puoi utilizzare System.Enum come variabile che accetterà SOLO i valori di enumerazione e puoi accedere al nome o al valore del tipo di valore dell'enumerazione tramite questa classe.

Ad esempio:

        // 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));

L'output del codice precedente:

9

9

Blue

Mi piace la risposta accettata di @Marc Gravell. Dato che sono un principiante di StackOverflow non mi è permesso commentare. Ma vorrei aggiungere che è utile controllare anche il Tipo di base dell'enum, specialmente se si utilizza l'attributo Flag e si preformano le operazioni di test dei flag bit-saggio ...

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

Ecco una soluzione che funziona per me:

nella classe genitore, dichiarare il campo come int, non come enum:

protected int state;

in modo che la classe genitore possa ancora utilizzare questo valore come int, al fine di fornire la serializzazione e la deserializionamento di questo valore su disco.

Quindi, chi sovrascrive la classe può farlo:

enum states{
  state1, state2
}

this.state = state1.toInt();

e può accedere al valore reale in questo modo:

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

dove toInt () è definito in una classe statica come segue:

public static class Utils
{

    public static int toInt(this state s)
    {
        return (int)s;
    }
 }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top