Enum "héritage"

391

J'ai une énumération dans un espace de noms de bas niveau. Je voudrais fournir une classe ou une énumération dans un espace de noms de niveau intermédiaire qui «hérite» de l'énumération de bas niveau.

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

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

J'espère que cela est possible, ou peut-être une sorte de classe qui peut remplacer la consommation d'énumération qui fournira une couche d'abstraction pour l'énumération, mais laisser encore une instance de cette classe accéder à l'énumération.

Pensées?

EDIT: L'une des raisons pour lesquelles je ne viens pas de passer à consts dans les classes est que l'énumération de bas niveau est nécessaire à un service que je dois consommer. On m'a donné les WSDL et les XSD, qui définissent la structure comme une énumération. Le service ne peut pas être modifié.

CodeMonkey1313
la source
1
Une option est codeproject.com/Articles/20805/Enhancing-C-Enums
Walter Vehoeven

Réponses:

462

Ce n'est pas possible. Les énumérations ne peuvent pas hériter d'autres énumérations. En fait, tous les énumérations doivent hériter de System.Enum. C # permet à la syntaxe de changer la représentation sous-jacente des valeurs d'énumération qui ressemble à l'héritage, mais en réalité, elles héritent toujours de System.enum.

Voir la section 8.5.2 de la spécification CLI pour les détails complets. Informations pertinentes de la spécification

  • Toutes les énumérations doivent provenir de System.Enum
  • En raison de ce qui précède, toutes les énumérations sont des types de valeur et sont donc scellées
JaredPar
la source
2
Et tous les types de valeurs dérivent de System.ValueType
Raz Megrelidze
4
Je dois mentionner que la réponse de @Seven est une solution de contournement légitime: stackoverflow.com/a/4042826/538387
Tohid
mais la réponse de @ Steven ne peut pas être utilisée dans une switchsituation.
zionpi
@zionpi oui mais notez que (je crois) le commutateur standard est compilé dans le même code IL comme un bloc complet if, else if, else: ce qui, je pense, a une meilleure syntaxe meilleure de toute façon. Vous perdez la capacité pour resharper / VS de compléter automatiquement toutes les déclarations de cas, mais je pense que ce n'est pas la fin du monde. C'est une préférence personnelle, mais je ne suis pas fan de la déclaration de changement.
MemeDeveloper
165

Vous pouvez réaliser ce que vous voulez avec des cours:

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

Maintenant, vous pouvez utiliser ces classes de la même manière que lorsqu'elles étaient des énumérations:

int i = Consume.B;

Mise à jour (après votre mise à jour de la question):

Si vous affectez les mêmes valeurs int aux constantes définies dans l'énumération existante, vous pouvez effectuer un cast entre l'énumération et les constantes, par exemple:

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;
M4N
la source
8
Comment énumérez-vous alors les champs de cette classe? Pour moi, c'est un comportement important d'une énumération:Enum.GetValues(typeof(MyEnum)
Mike de Klerk
1
Vous pouvez utiliser la réflexion: void Test() { foreach (System.Reflection.PropertyInfo pi in typeof(Consume).GetProperties()) { Console.WriteLine(pi.Name); } }
mnieto
2
Vous devez vous assurer que le regroupement de propriétés avec réflexion ignore les propriétés d'objet héritées.
Robert
La réflexion est super moche pour cette tâche.
dylanh724
1
Pas besoin d'utiliser Reflection, l'implémentation sur codeproject.com/Articles/20805/Enhancing-C-Enums est un bon moyen de le faire, car les objets sont en cours de création, ils sont ajoutés à une liste et cette liste peut être utilisée pour renvoie une liste de types d'objets. Lorsque vous le mélangez avec l'héritage, vous devez vous assurer que vous utilisez la bonne liste pour les classes héritées.
PBo
112

La réponse courte est non. Vous pouvez jouer un peu, si vous le souhaitez:

Vous pouvez toujours faire quelque chose comme ça:

private enum Base
{
    A,
    B,
    C
}

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

Mais cela ne fonctionne pas très bien parce que Base.A! = Consume.A

Vous pouvez toujours faire quelque chose comme ça, cependant:

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

Pour croiser Base et Consommer ...

Vous pouvez également convertir les valeurs des énumérations en nombres entiers et les comparer en tant qu'ints au lieu d'énumérations, mais ce type est également nul.

Le retour de la méthode d'extension doit taper cast it type T.

Brian Genisio
la source
4
Je creuse ça, mec. J'ai utilisé ce concept pour faire bouillir quelques énumérations de mon ORM vers mon interface publique (à celles sans la référence ORM).
ObjectType
5
On peut jeter des énumérations pour comparer au travail:Base.A == (Base)Consume.A
Kresimir
1
Utiliser (décimal) Base.A == (décimal) Consommer.A. Raison: Voici comment fonctionne la combinaison indicateur / masque de bit (par exemple, exemple dans Enum.IsDefined msdn.microsoft.com/en-us/library/… ). Ainsi, une énumération peut être définie sur un entier non défini dans l'énumération. Test de consommation = 123456;
TamusJRoyce
3
@TamusJRoyce décimal? intaurait beaucoup plus de sens. Quand un enum aurait-il une partie fractionnaire!?!?!
ErikE
Au moins, cela garantit que les constantes d'énumération correspondantes ont la même valeur entière. Après tout, les énumérations ne sont qu'un ensemble de constantes entières. C # n'impose pas que les valeurs affectées soient des constantes d'énumération vaild, c'est-à-dire que les énumérations ne sont pas de type sécurisé au sens strict.
Olivier Jacot-Descombes
98

Les solutions ci-dessus utilisant des classes avec des constantes int manquent de sécurité de type. C'est-à-dire que vous pourriez inventer de nouvelles valeurs réellement non définies dans la classe. De plus il n'est pas possible par exemple d'écrire une méthode prenant une de ces classes en entrée.

Vous auriez besoin d'écrire

public void DoSomethingMeaningFull(int consumeValue) ...

Cependant, il existe une solution basée sur les classes de l'ancien temps de Java, quand il n'y avait pas d'énumérations disponibles. Cela fournit un comportement presque énuméré. La seule mise en garde est que ces constantes ne peuvent pas être utilisées dans une instruction 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) { /* ... */ }
    // ...
}
Sept
la source
7
je pense que c'est la bonne réponse. Vous ne pouvez pas avoir d'héritage pour Enum mais cela peut vous permettre de le gérer!
robob
11
Agréable et propre. +1. Juste un indice, vous n'avez vraiment pas besoin du tout de la valeur int.
Ignacio Soler Garcia
1
Je n'ai jamais pensé aux énumérations comme si vous pouviez dire FileOpenMode.Read> FileOpenMode.Write. Si tel est le cas, vous avez besoin d'un int ou encore mieux d'un IEqualityComparer pour cette énumération. Cordialement.
Ignacio Soler Garcia
3
@binki en utilisant des valeurs aléatoires objectrendrait les valeurs différentes pour chaque instanciation de l'assembly afin qu'elles ne puissent pas être sérialisées.
ivan_pozdeev
2
Mais cela ne vous permet pas de "basculer" sur MyEnum, n'est-ce pas? Je veux dire, c'est principalement pourquoi j'utilise des énumérations ...
MemphiZ
13

Ignorant le fait que la base est un mot réservé, vous ne pouvez pas faire d'héritage d'énumération.

La meilleure chose que vous puissiez faire est quelque chose comme ça:

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

Comme ils sont tous du même type de base (c'est-à-dire: int), vous pouvez attribuer la valeur d'une instance d'un type à l'autre qui est castée. Pas idéal mais ça marche.

Pascal
la source
2
la base est réservée mais la base ne l'est pas
erikkallen
2
Il fait référence à l'utilisation de la base par l'OP comme nom d'énumération, c'est juste un exemple de nom, je suis sûr
John Rasch
Identique à la réponse de Genisio.
nawfal
6

Je sais que cette réponse est un peu tard mais c'est ce que j'ai fini par faire:

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        
}

Ensuite, je suis capable de faire des choses comme:

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)
{
}
Tono Nam
la source
2
Les nombres magiques peuvent être remplacés par des objets selon stackoverflow.com/questions/757684/… . Mais pour ce cas particulier, vous pouvez tirer le meilleur parti des deux mondes en utilisant les caractéristiques de la nomenclature biologique existante pour garantir l'unicité.
ivan_pozdeev
4

C'est ce que j'ai fait. Ce que j'ai fait différemment, c'est utiliser le même nom et le newmot - clé sur le "consommer" enum. Étant donné que le nom du enumest le même, vous pouvez simplement l'utiliser sans réfléchir et il aura raison. De plus, vous obtenez l'intellisense. Il vous suffit de vous assurer manuellement lors de la configuration que les valeurs sont copiées depuis la base et de les garder synchronisées. Vous pouvez aider cela avec des commentaires de code. C'est une autre raison pour laquelle dans la base de données lors du stockage des enumvaleurs, je stocke toujours la chaîne, pas la valeur. Parce que si vous utilisez des valeurs entières croissantes attribuées automatiquement, celles-ci peuvent changer avec le temps.

// 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
    }
}
toddmo
la source
2
Envisagez de définir une plage différente pour les nouvelles valeurs dans la classe dérivée (par exemple SmallMedium = 100,), afin de pouvoir conserver la compatibilité avec les anciennes versions de votre logiciel lorsque vous ajoutez de nouvelles valeurs dans la classe de base. Par exemple, l'ajout d'une Hugetaille dans votre énumération de base attribuerait 4à sa valeur, mais 4est déjà repris par SmallMediumdans la classe dérivée.
Roberto
1
@Roberto, Pour résoudre ce problème, je ne persiste jamais les valeurs d'énumération, mais uniquement les noms. Et les garder synchronisés est une exigence ici. Donc, l'ajout Hugede la classe de base nécessiterait un Hugedans la sous-classe avantSmallMedium
toddmo
2
BaseBallpeut-être pas le nom le plus intelligent ici. C'est confus. Depuis un baseball est en fait une chose. Si vous manquez qu'il ne s'agit que d'une classe de base pour le ballon, il semble très étrange qu'un volley-ball hérite d'un baseball physiquement plus petit :). Ma suggestion est d'utiliser simplementBall
Nick N.
3

Solution alternative

Dans mon entreprise, nous évitons de «sauter par-dessus les projets» pour accéder à des projets de niveau inférieur non communs. Par exemple, notre couche présentation / API ne peut référencer que notre couche domaine, et la couche domaine ne peut référencer que la couche données.

Toutefois, cela pose problème lorsqu'il existe des énumérations qui doivent être référencées à la fois par la présentation et les couches de domaine.

Voici la solution que nous avons implémentée (jusqu'à présent). C'est une assez bonne solution et fonctionne bien pour nous. Les autres réponses frappaient tout autour.

La prémisse de base est que les énumérations ne peuvent pas être héritées - mais les classes le peuvent. Donc...

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

Ensuite, pour "hériter" des énumérations dans un autre projet de niveau supérieur ...

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

Cela présente trois avantages réels ...

  1. Les définitions d'énumération sont automatiquement les mêmes dans les deux projets - par définition.
  2. Toutes les modifications apportées aux définitions d'énumération sont automatiquement répercutées dans la seconde sans avoir à apporter de modifications à la deuxième classe.
  3. Les énumérations sont basées sur le même code - les valeurs peuvent donc être facilement comparées (avec certaines mises en garde).

Pour référencer les énumérations dans le premier projet , vous pouvez utiliser le préfixe de la classe: BaseEnums.StatusType.Pending ou ajouter un "using static BaseEnums;" déclaration à vos utilisations.

Cependant, dans le deuxième projet, lorsque je traitais avec la classe héritée, je ne pouvais pas faire fonctionner l'approche "using static ..." , donc toutes les références aux "énumérations héritées" seraient préfixées avec la classe, par exemple SubEnums.StatusType.Pending . Si quelqu'un trouve un moyen d'autoriser l' utilisation de l' approche "en utilisant statique" dans le deuxième projet, faites-le moi savoir.

Je suis sûr que cela peut être modifié pour le rendre encore meilleur - mais cela fonctionne réellement et j'ai utilisé cette approche dans des projets de travail.

Veuillez voter positivement si vous le jugez utile.

Thomas Phaneuf
la source
2

J'ai également voulu surcharger Enums et créé un mélange de la réponse de 'Seven' sur cette page et de la réponse de 'Merlyn Morgan-Graham' sur un article en double de ceci , plus quelques améliorations.
Principaux avantages de ma solution par rapport aux autres:

  • incrément automatique de la valeur int sous-jacente
  • dénomination automatique

Il s'agit d'une solution prête à l'emploi et peut être directement insérée dans votre projet. Il est conçu pour mes besoins, donc si vous n'aimez pas certaines parties, remplacez-les simplement par votre propre code.

Tout d'abord, il y a la classe de base CEnumdont toutes les énumérations personnalisées doivent hériter. Il a la fonctionnalité de base, similaire au Enumtype .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;
    }
  }
}

Deuxièmement, voici 2 classes Enum dérivées. Toutes les classes dérivées ont besoin de quelques méthodes de base pour fonctionner comme prévu. C'est toujours le même code passe-partout; Je n'ai pas encore trouvé de moyen de l'externaliser à la classe de base. Le code du premier niveau d'héritage diffère légèrement de tous les niveaux suivants.

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

Les classes ont été testées avec succès avec le code suivant:

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
}
Tobias Knauss
la source
1

Les énumérations ne sont pas des classes réelles, même si elles y ressemblent. En interne, ils sont traités comme leur type sous-jacent (par défaut Int32). Par conséquent, vous ne pouvez le faire qu'en "copiant" des valeurs uniques d'une énumération à une autre et en les convertissant en leur nombre entier pour les comparer pour l'égalité.

Lucero
la source
1

Les énumérations ne peuvent pas être dérivées d'autres énumérations, mais uniquement de int, uint, short, ushort, long, ulong, byte et sbyte.

Comme Pascal l'a dit, vous pouvez utiliser d'autres valeurs ou constantes d'énumération pour initialiser une valeur d'énumération, mais c'est tout.

Jeroen Landheer
la source
8
C'est un peu impropre à cause de la syntaxe c # mais les énumérations ne peuvent pas réellement hériter de int, uint, etc ... Sous le capot, elles héritent toujours de System.Enum. C'est juste que le membre représentant l'énumération est tapé à l'int, uint, etc ...
JaredPar
@JaredPar. Quand une énumération est dérivée d'une uint, cela signifie que ses valeurs sont toutes des uint, etc. Par défaut, une énumération hérite de int. (Jetez un oeil à la spécification C #, enum SomeEnum: uint {...} fonctionne réellement.)
Jeroen Landheer
4
En fait non. Il hérite de System.enum. Comme indiqué précédemment et plus souvent ici, ce que vous pensez être l'héritage n'est qu'une ambiguïté langauge dans csharp.
TomTom
1

une autre solution possible:

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

ShloEmi
la source
1

Ce n'est pas possible (comme @JaredPar déjà mentionné). Essayer de mettre la logique autour de cela est une mauvaise pratique. Si vous avez un base classqui ont un enum, vous devez la liste de tous les possibles enum-valueslà - bas, et la mise en œuvre de la classe doit travailler avec les valeurs qu'il connaît.

Par exemple, supposons que vous ayez une classe de base BaseCataloget qu'elle ait un enum ProductFormats( Digital, Physical). Ensuite, vous pouvez avoir un MusicCatalogou BookCatalogqui pourrait contenir à la fois Digitalet des Physicalproduits, mais si la classe est ClothingCatalog, elle ne doit contenir que des Physicalproduits.

Jaider
la source
1

Je me rends compte que je suis un peu en retard à cette fête, mais voici mes deux cents.

Nous savons tous clairement que l'héritage Enum n'est pas pris en charge par le cadre. Certaines solutions de contournement très intéressantes ont été suggérées dans ce fil de discussion, mais aucun d'entre eux ne ressemblait tout à fait à ce que je cherchais, alors j'ai moi-même essayé.

Présentation: ObjectEnum

Vous pouvez vérifier le code et la documentation ici: https://github.com/dimi3tron/ObjectEnum .

Et le package ici: https://www.nuget.org/packages/ObjectEnum

Ou installez-le simplement: Install-Package ObjectEnum

En bref, ObjectEnum<TEnum> agit comme un wrapper pour toute énumération. En remplaçant GetDefinedValues ​​() dans les sous-classes, on peut spécifier quelles valeurs d'énumération sont valides pour cette classe spécifique.

Un certain nombre de surcharges d’opérateurs ont été ajoutées pour ObjectEnum<TEnum> instance se comporte comme si elle était une instance de l'énumération sous-jacente, en gardant à l'esprit les restrictions de valeur définies. Cela signifie que vous pouvez facilement comparer l'instance à une valeur int ou enum, et donc l'utiliser dans un cas de commutateur ou tout autre conditionnel.

Je voudrais me référer à la mention de dépôt github ci-dessus pour des exemples et des informations supplémentaires.

J'espère que vous trouvez ça utile. N'hésitez pas à commenter ou à ouvrir un problème sur github pour d'autres réflexions ou commentaires.

Voici quelques exemples de ce que vous pouvez faire avec 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;
}
Dimitri Troncquo
la source
-8

Vous pouvez effectuer l'héritage dans enum, mais il est limité aux types suivants uniquement. int, uint, octet, sbyte, court, ushort, long, ulong

Par exemple

public enum Car:int{
Toyota,
Benz,
}
Sriwantha Attanayake
la source
2
Je pense que l'OP demandait d'hériter une énumération d'une autre, pas seulement d'un type numérique de base (ce que toutes les énumérations font en C #, implicitement ou explicitement.)
reirab