Enum "Ereditarietà"


391

Ho un enum in uno spazio dei nomi di basso livello. Vorrei fornire una classe o un enum in uno spazio dei nomi di livello medio che "eredita" l'enum di basso livello.

namespace low
{
   public enum base
   {
      x, y, z
   }
}

namespace mid
{
   public enum consume : low.base
   {
   }
}

Spero che ciò sia possibile, o forse un qualche tipo di classe che possa prendere il posto del consumo di enum che fornirà uno strato di astrazione per l'enum, ma che permetta comunque a un'istanza di quella classe di accedere all'enum.

Pensieri?

EDIT: Uno dei motivi per cui non ho appena trasformato questo in costi in classe è che l'enum di basso livello è necessario per un servizio che devo consumare. Mi sono stati dati i WSDL e gli XSD, che definiscono la struttura come un enum. Il servizio non può essere modificato.


Risposte:


462

Non è possibile. Gli enum non possono ereditare da altri enum. In effetti tutti gli enum devono effettivamente ereditare System.Enum. C # consente alla sintassi di modificare la rappresentazione sottostante dei valori enum che sembra ereditarietà, ma in realtà ereditano ancora da System.enum.

Vedere la sezione 8.5.2 delle specifiche CLI per i dettagli completi. Informazioni pertinenti dalle specifiche

  • Tutti gli enum devono derivare System.Enum
  • A causa di quanto sopra, tutti gli enum sono tipi di valore e quindi sigillati

2
E tutti i tipi di valore derivano da System.ValueType
Raz Megrelidze

4
Devo dire che la risposta @Seven 's è una soluzione legittima: stackoverflow.com/a/4042826/538387
Tohid

ma la risposta di @ Steven non può essere utilizzata in switchsituazioni.
zionpi,

@zionpi sì, ma nota che (credo) lo switch standard viene compilato nello stesso codice IL come un blocco completo se, altrimenti se, altrimenti: che penso abbia comunque una migliore sintassi migliore. Hai perso la capacità del resharper / VS di completare automaticamente tutte le dichiarazioni del caso, ma penso che non sia la fine del mondo. È una preferenza personale ma non sono un fan dell'istruzione switch.
MemeDeveloper

165

Puoi ottenere ciò che vuoi con le lezioni:

public class Base
{
    public const int A = 1;
    public const int B = 2;
    public const int C = 3;
}
public class Consume : Base
{
    public const int D = 4;
    public const int E = 5;
}

Ora puoi usare queste classi simili come quando erano enumerazioni:

int i = Consume.B;

Aggiornamento (dopo l'aggiornamento della domanda):

Se si assegnano gli stessi valori int alle costanti definite nell'enum esistente, è possibile eseguire il cast tra l'enum e le costanti, ad esempio:

public enum SomeEnum // this is the existing enum (from WSDL)
{
    A = 1,
    B = 2,
    ...
}
public class Base
{
    public const int A = (int)SomeEnum.A;
    //...
}
public class Consume : Base
{
    public const int D = 4;
    public const int E = 5;
}

// where you have to use the enum, use a cast:
SomeEnum e = (SomeEnum)Consume.B;

8
Come si elencano quindi i campi in questa classe? Per me questo è un comportamento importante di un enum:Enum.GetValues(typeof(MyEnum)
Mike de Klerk,

1
Puoi usare la riflessione: void Test() { foreach (System.Reflection.PropertyInfo pi in typeof(Consume).GetProperties()) { Console.WriteLine(pi.Name); } }
mnieto il

2
Dovresti assicurarti che la raccolta di proprietà con la riflessione ignori le proprietà degli oggetti ereditate.
Robert,

La riflessione è super brutta per quel compito.
dylanh724

1
Non è necessario utilizzare Reflection, l'implementazione su codeproject.com/Articles/20805/Enhancing-C-Enums è un buon modo per farlo, poiché gli oggetti vengono creati, vengono aggiunti a un elenco e tale elenco può essere utilizzato per restituisce un elenco di tipi di oggetti. Quando lo mescoli con l'ereditarietà, dovrai assicurarti di utilizzare l'elenco giusto per le classi ereditarie.
PBo

112

La risposta breve è no. Puoi giocare un po ', se vuoi:

Puoi sempre fare qualcosa del genere:

private enum Base
{
    A,
    B,
    C
}

private enum Consume
{
    A = Base.A,
    B = Base.B,
    C = Base.C,
    D,
    E
}

Ma non funziona così bene perché Base.A! = Consume.A

Puoi sempre fare qualcosa del genere, però:

public static class Extensions
{
    public static T As<T>(this Consume c) where T : struct
    {
        return (T)System.Enum.Parse(typeof(T), c.ToString(), false);
    }
}

Al fine di attraversare tra Base e Consumo ...

Potresti anche lanciare i valori degli enum come ints e confrontarli come in invece di enum, ma anche questo tipo di schifo.

Il metodo di estensione return deve digitare cast it type T.


4
Lo scavo, amico. Ho usato questo concetto per creare bolle dal mio ORM alla mia interfaccia pubblica (a quelle senza riferimento ORM).
ObjectType

5
Si può lanciare enumerazioni per il confronto per lavorare:Base.A == (Base)Consume.A
Kresimir,

1
Usa (decimale) Base.A == (decimale) Consume.A. Motivo: Questo è come indicatore di bit / maschera opere conciliano (es esempio in Enum.IsDefined msdn.microsoft.com/en-us/library/... ). Quindi un enum può essere impostato su un numero intero non definito nell'enum. Consuma test = 123456;
TamusJRoyce,

3
@TamusJRoyce decimale? intavrebbe molto più senso. Quando un enum avrebbe una parte frazionaria!?!?!
ErikE,

Almeno, questo assicura che le costanti enum corrispondenti abbiano lo stesso valore intero. Dopotutto, gli enum sono solo un insieme di costanti intere. C # non impone che i valori assegnati siano costanti di enum Vaild, vale a dire che gli enum non sono sicuri in senso stretto.
Olivier Jacot-Descombes,

98

Le soluzioni di cui sopra che utilizzano classi con costanti int mancano di sicurezza del tipo. Vale a dire che potresti inventare nuovi valori attualmente non definiti nella classe. Inoltre, ad esempio, non è possibile scrivere un metodo prendendo come input una di queste classi.

Dovresti scrivere

public void DoSomethingMeaningFull(int consumeValue) ...

Tuttavia, esiste una soluzione basata sulla classe dei vecchi tempi di Java, quando non erano disponibili enumerazioni. Ciò fornisce un comportamento quasi enumatico. L'unica avvertenza è che queste costanti non possono essere utilizzate all'interno di un'istruzione switch.

public class MyBaseEnum
{
    public static readonly MyBaseEnum A = new MyBaseEnum( 1 );
    public static readonly MyBaseEnum B = new MyBaseEnum( 2 );
    public static readonly MyBaseEnum C = new MyBaseEnum( 3 );

    public int InternalValue { get; protected set; }

    protected MyBaseEnum( int internalValue )
    {
        this.InternalValue = internalValue;
    }
}

public class MyEnum : MyBaseEnum
{
    public static readonly MyEnum D = new MyEnum( 4 );
    public static readonly MyEnum E = new MyEnum( 5 );

    protected MyEnum( int internalValue ) : base( internalValue )
    {
        // Nothing
    }
}

[TestMethod]
public void EnumTest()
{
    this.DoSomethingMeaningful( MyEnum.A );
}

private void DoSomethingMeaningful( MyBaseEnum enumValue )
{
    // ...
    if( enumValue == MyEnum.A ) { /* ... */ }
    else if (enumValue == MyEnum.B) { /* ... */ }
    // ...
}

7
penso che questa sia la risposta giusta. Non puoi avere eredità per Enum ma questo può permetterti di gestirlo!
robob

11
Bello e pulito. +1. Solo un suggerimento, non hai davvero bisogno del valore int.
Ignacio Soler Garcia,

1
Non ho mai pensato alle enumerazioni come se potessi dire FileOpenMode.Read> FileOpenMode.Write. Se questo è il caso, allora hai bisogno di un int o anche meglio di IEqualityComparer per quell'enum. Saluti.
Ignacio Soler Garcia,

3
L'utilizzo di @binki in random objectrenderebbe i valori diversi per ogni istanza dell'assembly in modo che non possano essere serializzati.
Ivan_pozdeev,

2
Ma questo non ti permette di "accendere" su MyEnum, vero? Voglio dire, è principalmente per questo che uso gli enum ...
MemphiZ,

13

Ignorando il fatto che base è una parola riservata, non puoi fare l'eredità di enum.

La cosa migliore che potresti fare è qualcosa del genere:

public enum Baseenum
{
   x, y, z
}

public enum Consume
{
   x = Baseenum.x,
   y = Baseenum.y,
   z = Baseenum.z
}

public void Test()
{
   Baseenum a = Baseenum.x;
   Consume newA = (Consume) a;

   if ((Int32) a == (Int32) newA)
   {
   MessageBox.Show(newA.ToString());
   }
}

Dal momento che sono tutti dello stesso tipo di base (cioè: int) è possibile assegnare il valore da un'istanza di un tipo a un altro che un cast. Non ideale ma funziona.


2
la base è riservata ma la base no
erikkallen il

2
Si riferisce all'uso della base da parte dell'OP come nome dell'enum, ne sono sicuro solo un esempio
John Rasch,

Come la risposta di Genisio.
nawfal,

6

So che questa risposta è un po 'in ritardo, ma questo è quello che ho finito per fare:

public class BaseAnimal : IEquatable<BaseAnimal>
{
    public string Name { private set; get; }
    public int Value { private set; get; }

    public BaseAnimal(int value, String name)
    {
        this.Name = name;
        this.Value = value;
    }

    public override String ToString()
    {
        return Name;
    }

    public bool Equals(BaseAnimal other)
    {
        return other.Name == this.Name && other.Value == this.Value;
    }
}

public class AnimalType : BaseAnimal
{
    public static readonly BaseAnimal Invertebrate = new BaseAnimal(1, "Invertebrate");

    public static readonly BaseAnimal Amphibians = new BaseAnimal(2, "Amphibians");

    // etc        
}

public class DogType : AnimalType
{
    public static readonly BaseAnimal Golden_Retriever = new BaseAnimal(3, "Golden_Retriever");

    public static readonly BaseAnimal Great_Dane = new BaseAnimal(4, "Great_Dane");

    // etc        
}

Quindi sono in grado di fare cose come:

public void SomeMethod()
{
    var a = AnimalType.Amphibians;
    var b = AnimalType.Amphibians;

    if (a == b)
    {
        // should be equal
    }

    // call method as
    Foo(a);

    // using ifs
    if (a == AnimalType.Amphibians)
    {
    }
    else if (a == AnimalType.Invertebrate)
    {
    }
    else if (a == DogType.Golden_Retriever)
    {
    }
    // etc          
}

public void Foo(BaseAnimal typeOfAnimal)
{
}

2
I numeri magici possono essere sostituiti con oggetti come stackoverflow.com/questions/757684/… . Ma per questo caso particolare, puoi ottenere il meglio da entrambi i mondi usando le caratteristiche della nomenclatura biologica esistente per garantire l'unicità.
ivan_pozdeev il

4

Questo è quello che ho fatto. Quello che ho fatto diversamente è usare lo stesso nome e la newparola chiave su "consumo" enum. Dal momento che il nome enumè lo stesso, puoi semplicemente usarlo senza pensarci e sarà giusto. Inoltre ottieni intellisense. Devi solo fare attenzione manualmente durante l'impostazione che i valori vengano copiati dalla base e mantenerli sincronizzati. Puoi aiutarlo insieme ai commenti sul codice. Questo è un altro motivo per cui nel database durante la memorizzazione dei enumvalori memorizzo sempre la stringa, non il valore. Perché se si utilizzano valori interi crescenti assegnati automaticamente, questi possono cambiare nel tempo.

// Base Class for balls 
public class BaseBall
{
    // keep synced with subclasses!
    public enum Sizes
    {
        Small,
        Medium,
        Large
    }
}

public class VolleyBall : BaseBall
{
    // keep synced with base class!
    public new enum Sizes
    {
        Small = BaseBall.Sizes.Small,
        Medium = BaseBall.Sizes.Medium,
        Large = BaseBall.Sizes.Large,
        SmallMedium,
        MediumLarge,
        Ginormous
    }
}

2
Valuta di impostare un intervallo diverso per i nuovi valori nella classe derivata (ad es. SmallMedium = 100,), In modo da poter mantenere la compatibilità con le versioni precedenti del tuo software quando aggiungi nuovi valori nella classe base. Ad esempio, l'aggiunta di una Hugedimensione nel tuo enum di base assegnerebbe 4al suo valore, ma 4è già presa dalla SmallMediumclasse derivata.
Roberto,

1
@Roberto, per affrontare questo, non persisto mai valori enum, ma solo i nomi. E mantenerli sincronizzati è un requisito qui. Quindi l'aggiunta Hugenella classe base avrebbe bisogno di una Hugesottoclasse primaSmallMedium
toddmo

2
BaseBallpotrebbe non essere il nome più intelligente qui. È confuso. Dal momento che una palla da baseball è in realtà una cosa. Se ti manca che questa è solo una classe base per la palla, sembra molto strano che una pallavolo erediti da una palla da baseball fisicamente più piccola :). Il mio suggerimento è di usare soloBall
Nick N.

3

Soluzione alternativa

Nella mia azienda, evitiamo di "saltare i progetti" per arrivare a progetti di livello inferiore non comuni. Ad esempio, il nostro livello di presentazione / API può solo fare riferimento al nostro livello di dominio e il livello di dominio può solo fare riferimento al livello di dati.

Tuttavia, questo è un problema quando ci sono enumerati che devono essere referenziati sia dalla presentazione che dai livelli del dominio.

Ecco la soluzione che abbiamo implementato (finora). È una soluzione abbastanza buona e funziona bene per noi. Le altre risposte stavano colpendo tutto intorno a questo.

La premessa di base è che gli enum non possono essere ereditati, ma le classi possono. Così...

// In the lower level project (or DLL)...
public abstract class BaseEnums
{
    public enum ImportanceType
    {
        None = 0,
        Success = 1,
        Warning = 2,
        Information = 3,
        Exclamation = 4
    }

    [Flags]
    public enum StatusType : Int32
    {
        None = 0,
        Pending = 1,
        Approved = 2,
        Canceled = 4,
        Accepted = (8 | Approved),
        Rejected = 16,
        Shipped = (32 | Accepted),
        Reconciled = (64 | Shipped)
    }

    public enum Conveyance
    {
        None = 0,
        Feet = 1,
        Automobile = 2,
        Bicycle = 3,
        Motorcycle = 4,
        TukTuk = 5,
        Horse = 6,
        Yak = 7,
        Segue = 8
    }

Quindi, per "ereditare" gli enum in un altro progetto di livello superiore ...

// Class in another project
public sealed class SubEnums: BaseEnums
{
   private SubEnums()
   {}
}

Questo ha tre vantaggi reali ...

  1. Le definizioni enum sono automaticamente le stesse in entrambi i progetti, per definizione.
  2. Eventuali modifiche alle definizioni di enum vengono automaticamente ripetute nella seconda senza dover apportare modifiche alla seconda classe.
  3. Gli enum si basano sullo stesso codice, quindi i valori possono essere facilmente confrontati (con alcuni avvertimenti).

Per fare riferimento agli enumerazioni nel primo progetto , è possibile utilizzare il prefisso della classe: BaseEnums.StatusType.Pending o aggiungere un "utilizzo di BaseEnums statici;" dichiarazione ai tuoi usi.

Nel secondo progetto , tuttavia, quando ho a che fare con la classe ereditata, non sono riuscito a far funzionare l' approccio "using static ..." , quindi tutti i riferimenti agli "enumerativi ereditati" sarebbero preceduti dalla classe, ad esempio SubEnums.StatusType.Pending . Se qualcuno trova un modo per consentire l' approccio "using static" da utilizzare nel secondo progetto, fammelo sapere.

Sono sicuro che questo può essere modificato per renderlo ancora migliore, ma in realtà funziona e ho usato questo approccio in progetti di lavoro.

Per favore vota questo se lo ritieni utile.


2

Volevo anche sovraccaricare Enums e ho creato un mix della risposta di "Sette" in questa pagina e la risposta di "Merlyn Morgan-Graham" in un post duplicato di questo , oltre a un paio di miglioramenti.
Principali vantaggi della mia soluzione rispetto agli altri:

  • incremento automatico del valore int sottostante
  • denominazione automatica

Questa è una soluzione pronta all'uso e può essere inserita direttamente nel progetto. È progettato per le mie esigenze, quindi se non ti piacciono alcune parti, sostituiscile con il tuo codice.

Innanzitutto, esiste la classe base da CEnumcui dovrebbero ereditare tutti gli enum personalizzati. Ha le funzionalità di base, simili al Enumtipo .net :

public class CEnum
{
  protected static readonly int msc_iUpdateNames  = int.MinValue;
  protected static int          ms_iAutoValue     = -1;
  protected static List<int>    ms_listiValue     = new List<int>();

  public int Value
  {
    get;
    protected set;
  }

  public string Name
  {
    get;
    protected set;
  }

  protected CEnum ()
  {
    CommonConstructor (-1);
  }

  protected CEnum (int i_iValue)
  {
    CommonConstructor (i_iValue);
  }

  public static string[] GetNames (IList<CEnum> i_listoValue)
  {
    if (i_listoValue == null)
      return null;
    string[] asName = new string[i_listoValue.Count];
    for (int ixCnt = 0; ixCnt < asName.Length; ixCnt++)
      asName[ixCnt] = i_listoValue[ixCnt]?.Name;
    return asName;
  }

  public static CEnum[] GetValues ()
  {
    return new CEnum[0];
  }

  protected virtual void CommonConstructor (int i_iValue)
  {
    if (i_iValue == msc_iUpdateNames)
    {
      UpdateNames (this.GetType ());
      return;
    }
    else if (i_iValue > ms_iAutoValue)
      ms_iAutoValue = i_iValue;
    else
      i_iValue = ++ms_iAutoValue;

    if (ms_listiValue.Contains (i_iValue))
      throw new ArgumentException ("duplicate value " + i_iValue.ToString ());
    Value = i_iValue;
    ms_listiValue.Add (i_iValue);
  }

  private static void UpdateNames (Type i_oType)
  {
    if (i_oType == null)
      return;
    FieldInfo[] aoFieldInfo = i_oType.GetFields (BindingFlags.Public | BindingFlags.Static);

    foreach (FieldInfo oFieldInfo in aoFieldInfo)
    {
      CEnum oEnumResult = oFieldInfo.GetValue (null) as CEnum;
      if (oEnumResult == null)
        continue;
      oEnumResult.Name = oFieldInfo.Name;
    }
  }
}

In secondo luogo, qui ci sono 2 classi Enum derivate. Tutte le classi derivate necessitano di alcuni metodi di base per funzionare come previsto. È sempre lo stesso codice del boilerplate; Non ho ancora trovato il modo di esternalizzarlo alla classe base. Il codice del primo livello di eredità differisce leggermente da tutti i livelli successivi.

public class CEnumResult : CEnum
{
  private   static List<CEnumResult>  ms_listoValue = new List<CEnumResult>();

  public    static readonly CEnumResult Nothing         = new CEnumResult (  0);
  public    static readonly CEnumResult SUCCESS         = new CEnumResult (  1);
  public    static readonly CEnumResult UserAbort       = new CEnumResult ( 11);
  public    static readonly CEnumResult InProgress      = new CEnumResult (101);
  public    static readonly CEnumResult Pausing         = new CEnumResult (201);
  private   static readonly CEnumResult Dummy           = new CEnumResult (msc_iUpdateNames);

  protected CEnumResult () : base ()
  {
  }

  protected CEnumResult (int i_iValue) : base (i_iValue)
  {
  }

  protected override void CommonConstructor (int i_iValue)
  {
    base.CommonConstructor (i_iValue);

    if (i_iValue == msc_iUpdateNames)
      return;
    if (this.GetType () == System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType)
      ms_listoValue.Add (this);
  }

  public static new CEnumResult[] GetValues ()
  {
    List<CEnumResult> listoValue = new List<CEnumResult> ();
    listoValue.AddRange (ms_listoValue);
    return listoValue.ToArray ();
  }
}

public class CEnumResultClassCommon : CEnumResult
{
  private   static List<CEnumResultClassCommon> ms_listoValue = new List<CEnumResultClassCommon>();

  public    static readonly CEnumResult Error_InternalProgramming           = new CEnumResultClassCommon (1000);

  public    static readonly CEnumResult Error_Initialization                = new CEnumResultClassCommon ();
  public    static readonly CEnumResult Error_ObjectNotInitialized          = new CEnumResultClassCommon ();
  public    static readonly CEnumResult Error_DLLMissing                    = new CEnumResultClassCommon ();
  // ... many more
  private   static readonly CEnumResult Dummy                               = new CEnumResultClassCommon (msc_iUpdateNames);

  protected CEnumResultClassCommon () : base ()
  {
  }

  protected CEnumResultClassCommon (int i_iValue) : base (i_iValue)
  {
  }

  protected override void CommonConstructor (int i_iValue)
  {
    base.CommonConstructor (i_iValue);

    if (i_iValue == msc_iUpdateNames)
      return;
    if (this.GetType () == System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType)
      ms_listoValue.Add (this);
  }

  public static new CEnumResult[] GetValues ()
  {
    List<CEnumResult> listoValue = new List<CEnumResult> (CEnumResult.GetValues ());
    listoValue.AddRange (ms_listoValue);
    return listoValue.ToArray ();
  }
}

Le classi sono state testate con successo con il codice seguente:

private static void Main (string[] args)
{
  CEnumResult oEnumResult = CEnumResultClassCommon.Error_Initialization;
  string sName = oEnumResult.Name;   // sName = "Error_Initialization"

  CEnum[] aoEnumResult = CEnumResultClassCommon.GetValues ();   // aoEnumResult = {testCEnumResult.Program.CEnumResult[9]}
  string[] asEnumNames = CEnum.GetNames (aoEnumResult);
  int ixValue = Array.IndexOf (aoEnumResult, oEnumResult);    // ixValue = 6
}

1

Gli enum non sono classi reali, anche se sembrano simili. Internamente, sono trattati proprio come il loro tipo di base (per impostazione predefinita Int32). Pertanto, puoi farlo solo "copiando" singoli valori da un enum all'altro e lanciandoli al loro numero intero per confrontarli per l'uguaglianza.


1

Gli enum non possono essere derivati ​​da altri enum, ma solo da int, uint, short, ushort, long, ulong, byte e sbyte.

Come ha detto Pascal, puoi usare altri valori o costanti di enum per inizializzare un valore di enum, ma questo è tutto.


8
È un po 'un termine improprio a causa della sintassi c # ma l'enum non può effettivamente ereditare da int, uint, ecc ... Sotto il cofano ereditano ancora da System.Enum. È solo che il membro che rappresenta l'enum viene digitato in int, uint, ecc ...
JaredPar

@JaredPar. Quando un enum viene derivato da un uint, significa che i suoi valori sono tutti uint, ecc. Per impostazione predefinita un enum eredita int. (Dai un'occhiata alla specifica C #, enum SomeEnum: uint {...} funziona davvero.)
Jeroen Landheer,

4
In realtà no. Eredita System.enum. Come è stato pubblicato prima e più spesso qui, ciò che pensi sia eredità è solo una dusambiguità linguistica in csharp.
TomTom,

1

un'altra possibile soluzione:

public enum @base
{
    x,
    y,
    z
}

public enum consume
{
    x = @base.x,
    y = @base.y,
    z = @base.z,

    a,b,c
}

// TODO: Add a unit-test to check that if @base and consume are aligned

HTH


1

Questo non è possibile (come già menzionato @JaredPar). Cercare di mettere la logica al fine di aggirare questo è una cattiva pratica. Nel caso in base classcui ne possiedi uno enum, dovresti elencare tutto il possibile enum-valuese l'implementazione della classe dovrebbe funzionare con i valori che conosce.

Ad esempio, supponiamo che tu abbia una classe base BaseCataloge che abbia un enum ProductFormats( Digital, Physical). Quindi puoi avere un MusicCatalogo BookCatalogche può contenere entrambi Digitale Physicalprodotti, ma se la classe è ClothingCatalog, dovrebbe contenere solo Physicalprodotti.


1

Mi rendo conto di essere un po 'in ritardo per questa festa, ma ecco i miei due centesimi.

Siamo tutti chiari sul fatto che l'ereditarietà di Enum non è supportata dal framework. In questo thread sono state suggerite alcune soluzioni molto interessanti, ma nessuna di queste sembrava proprio quello che stavo cercando, quindi ho provato anche io.

Presentazione di: ObjectEnum

Puoi controllare il codice e la documentazione qui: https://github.com/dimi3tron/ObjectEnum .

E il pacchetto qui: https://www.nuget.org/packages/ObjectEnum

O semplicemente installalo: Install-Package ObjectEnum

In breve, ObjectEnum<TEnum>funge da involucro per qualsiasi enum. Sovrascrivendo GetDefinedValues ​​() nelle sottoclassi, è possibile specificare quali valori enum sono validi per questa specifica classe.

Sono stati aggiunti numerosi sovraccarichi di operatore per far sì che ObjectEnum<TEnum>un'istanza si comporti come se fosse un'istanza dell'enum sottostante, tenendo presente le restrizioni di valore definite. Ciò significa che puoi facilmente confrontare l'istanza con un valore int o enum e quindi usarla in un caso switch o in qualsiasi altro condizionale.

Vorrei fare riferimento alla citazione repository github sopra per esempi e ulteriori informazioni.

Spero che lo trovi utile Sentiti libero di commentare o aprire un problema su Github per ulteriori pensieri o commenti.

Ecco alcuni brevi esempi di cosa puoi fare con ObjectEnum<TEnum>:

var sunday = new WorkDay(DayOfWeek.Sunday); //throws exception
var monday = new WorkDay(DayOfWeek.Monday); //works fine
var label = $"{monday} is day {(int)monday}." //produces: "Monday is day 1."
var mondayIsAlwaysMonday = monday == DayOfWeek.Monday; //true, sorry...

var friday = new WorkDay(DayOfWeek.Friday);

switch((DayOfWeek)friday){
    case DayOfWeek.Monday:
        //do something monday related
        break;
        /*...*/
    case DayOfWeek.Friday:
        //do something friday related
        break;
}

-8

È possibile eseguire l'ereditarietà in enum, tuttavia è limitato ai seguenti tipi. int, uint, byte, sbyte, short, ushort, long, ulong

Per esempio

public enum Car:int{
Toyota,
Benz,
}

2
Credo che il PO è stato chiesto di ereditare un enum da un altro, non solo da un tipo numerico base (che tutte le enumerazioni fare in C #, implicitamente o esplicitamente.)
Reirab
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.