Enum "Herencia"

391

Tengo una enumeración en un espacio de nombres de bajo nivel. Me gustaría proporcionar una clase o enumeración en un espacio de nombres de nivel medio que "herede" la enumeración de bajo nivel.

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

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

Espero que esto sea posible, o tal vez algún tipo de clase que pueda ocupar el lugar del consumo de enumeración que proporcionará una capa de abstracción para la enumeración, pero aún así permitirá que una instancia de esa clase acceda a la enumeración.

Pensamientos?

EDITAR: Una de las razones por las que no acabo de cambiar esto a consts en clases es que un servicio que debo consumir necesita la enumeración de bajo nivel. Me dieron los WSDL y los XSD, que definen la estructura como una enumeración. El servicio no se puede cambiar.

CodeMonkey1313
fuente
1
Una opción es codeproject.com/Articles/20805/Enhancing-C-Enums
Walter Vehoeven

Respuestas:

462

Esto no es posible. Las enumeraciones no pueden heredar de otras enumeraciones. De hecho, todas las enumeraciones deben heredar de System.Enum. C # permite que la sintaxis cambie la representación subyacente de los valores de enumeración que parece herencia, pero en realidad todavía heredan de System.enum.

Consulte la sección 8.5.2 de la especificación de la CLI para obtener todos los detalles. Información relevante de la especificación

  • Todas las enumeraciones deben derivar de System.Enum
  • Debido a lo anterior, todas las enumeraciones son tipos de valor y, por lo tanto, están selladas
JaredPar
fuente
2
Y todos los tipos de valor se derivan de System.ValueType
Raz Megrelidze
44
Tengo que mencionar que la respuesta de @Seven es una solución legítima: stackoverflow.com/a/4042826/538387
Tohid
pero la respuesta de @ Steven no se puede usar en la switchsituación.
zionpi
@zionpi sí, pero tenga en cuenta que (creo) el conmutador estándar se compila en el mismo código IL que un bloque completo if, else if, else would: lo que creo que tiene una mejor sintaxis de todos modos. Se pierde la capacidad de resharper / VS para autocompletar todas las declaraciones de casos, pero creo que ese no es el fin del mundo. Es una preferencia personal, pero no soy fanático de la declaración de cambio.
MemeDeveloper
165

Puedes lograr lo que quieres con las clases:

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

Ahora puede usar estas clases de forma similar a cuando eran enumeraciones:

int i = Consume.B;

Actualización (después de su actualización de la pregunta):

Si asigna los mismos valores int a las constantes como se define en la enumeración existente, puede convertir entre la enumeración y las constantes, por ejemplo:

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
fuente
8
¿Cómo enumeras los campos en esta clase entonces? Para mí ese es un comportamiento importante de una enumeración:Enum.GetValues(typeof(MyEnum)
Mike de Klerk
1
Puede usar la reflexión: void Test() { foreach (System.Reflection.PropertyInfo pi in typeof(Consume).GetProperties()) { Console.WriteLine(pi.Name); } }
mnieto
2
Debería asegurarse de que la recopilación de propiedades con reflexión ignore las propiedades del objeto heredado.
Robert
La reflexión es súper fea para esa tarea.
dylanh724
1
No es necesario usar Reflection, la implementación en codeproject.com/Articles/20805/Enhancing-C-Enums es una buena manera de hacerlo, ya que los objetos se están creando, se agregan a una lista y esa lista se puede usar para devuelve una lista de tipos de objetos. Cuando lo mezcla con herencia, deberá asegurarse de estar utilizando la lista correcta para las clases heredadas.
PBo
112

La respuesta corta es no. Puedes jugar un poco, si quieres:

Siempre puedes hacer algo como esto:

private enum Base
{
    A,
    B,
    C
}

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

Pero, no funciona tan bien porque Base.A! = Consume.A

Sin embargo, siempre puedes hacer algo como esto:

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

Para cruzar entre Base y Consumir ...

También podría convertir los valores de las enumeraciones como ints, y compararlos como ints en lugar de enum, pero ese tipo de apesta también.

El método de extensión return debería escribir cast it type T.

Brian Genisio
fuente
44
Cavo esto, hombre. Usé este concepto para burbujear algunas enumeraciones de mi ORM a mi interfaz pública (a aquellas sin la referencia de ORM).
ObjectType
55
Uno puede emitir enumeraciones para compararlas con el trabajo:Base.A == (Base)Consume.A
Kresimir
1
Use (decimal) Base.A == (decimal) Consume.A. Motivo: así es como funciona la combinación de indicador / máscara de bits (por ejemplo, en Enum.IsDefined msdn.microsoft.com/en-us/library/… ). Por lo tanto, una enumeración se puede establecer en un número entero no definido en la enumeración. Prueba de consumo = 123456;
TamusJRoyce
3
@TamusJRoyce decimal? inttendría mucho más sentido. ¿Cuándo una enumeración tendría una parte fraccionaria?
ErikE
Al menos, esto asegura que las constantes enum correspondientes tengan el mismo valor entero. Después de todo, las enumeraciones son solo un conjunto de constantes enteras. C # no exige que los valores asignados sean constantes de enumeración vaild, es decir, las enumeraciones no son de tipo seguro en sentido estricto.
Olivier Jacot-Descombes
98

Las soluciones anteriores que usan clases con constantes int carecen de seguridad de tipo. Es decir, podría inventar nuevos valores realmente no definidos en la clase. Además, no es posible, por ejemplo, escribir un método tomando una de estas clases como entrada.

Necesitarías escribir

public void DoSomethingMeaningFull(int consumeValue) ...

Sin embargo, existe una solución basada en clases de los viejos tiempos de Java, cuando no había enumeraciones disponibles. Esto proporciona un comportamiento casi enum. La única advertencia es que estas constantes no se pueden usar dentro de una instrucción 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) { /* ... */ }
    // ...
}
Siete
fuente
77
Creo que esta es la respuesta correcta. ¡No puede tener herencia para Enum, pero esto puede permitirle administrarla!
robob 01 de
11
Bonito y limpio. +1. Solo una pista, realmente no necesitas el valor int en absoluto.
Ignacio Soler García
1
Nunca pensé en enumeraciones como si pudieras decir FileOpenMode.Read> FileOpenMode.Write. Si ese es el caso, entonces necesita un int o incluso mejor un IEqualityComparer para esa enumeración. Saludos.
Ignacio Soler Garcia
3
@binki usando random object's haría que los valores sean diferentes para cada instancia del ensamblado, por lo que no se pueden serializar.
ivan_pozdeev
2
Pero esto no le permite "cambiar" en MyEnum, ¿verdad? Quiero decir, eso es principalmente por qué uso enumeraciones ...
MemphiZ
13

Ignorando el hecho de que base es una palabra reservada, no se puede hacer la herencia de enum.

Lo mejor que puedes hacer es algo así:

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

Dado que todos son del mismo tipo base (es decir, int), puede asignar el valor de una instancia de un tipo a otro, que es una conversión. No es ideal pero funciona.

Pascal
fuente
2
base está reservada pero Base no lo está
erikkallen
2
Se refiere a la utilización de la OP de base como el nombre de enumeración, es sólo un nombre de ejemplo Estoy seguro
John Rasch
Igual que la respuesta de Genisio.
nawfal
6

Sé que esta respuesta es un poco tarde, pero esto es lo que terminé haciendo:

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        
}

Entonces puedo hacer cosas como:

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
fuente
2
Los números mágicos se pueden reemplazar con objetos según stackoverflow.com/questions/757684/… . Pero para este caso particular, puede obtener lo mejor de ambos mundos utilizando las características de la nomenclatura biológica existente para garantizar la unicidad.
ivan_pozdeev
4

Esto es lo que hice. Lo que he hecho de manera diferente es usar el mismo nombre y la newpalabra clave en el "consumidor" enum. Dado que el nombre del enummismo es el mismo, puede usarlo sin pensarlo y será correcto. Además, obtienes inteligencia. Solo debe tener cuidado manualmente al configurar que los valores se copien de la base y mantenerlos sincronizados. Puede ayudarlo junto con los comentarios de código. Esta es otra razón por la cual en la base de datos al almacenar enumvalores siempre almaceno la cadena, no el valor. Porque si está utilizando valores enteros crecientes asignados automáticamente, estos pueden cambiar con el tiempo.

// 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
fuente
2
Considere establecer un rango diferente para los nuevos valores en la clase derivada (por ejemplo SmallMedium = 100,), de modo que pueda mantener la compatibilidad con versiones anteriores de su software cuando agregue nuevos valores en la clase base. Por ejemplo, agregar un Hugetamaño en su enumeración base se asignaría 4a su valor, pero 4ya está SmallMediumen la clase derivada.
Roberto
1
@Roberto, para abordar esto, nunca persisto los valores de enumeración, sino solo los nombres. Y mantenerlos sincronizados es un requisito aquí. Por lo tanto, agregar Hugeen la clase base necesitaría un Hugeen la subclase antesSmallMedium
toddmo
2
BaseBallpuede no ser el nombre más inteligente aquí. Es confuso. Dado que una pelota de béisbol es realmente una cosa. Si te pierdes que esto es solo una clase base para la pelota, parece muy extraño que un voleibol herede de una pelota de béisbol físicamente más pequeña :). Mi sugerencia es simplemente usarBall
Nick N.
3

Solución alternativa

En mi empresa, evitamos "saltar sobre proyectos" para llegar a proyectos de nivel inferior no comunes. Por ejemplo, nuestra capa de presentación / API solo puede hacer referencia a nuestra capa de dominio, y la capa de dominio solo puede hacer referencia a la capa de datos.

Sin embargo, este es un problema cuando hay enumeraciones que deben ser referenciadas tanto por la presentación como por las capas de dominio.

Aquí está la solución que hemos implementado (hasta ahora). Es una solución bastante buena y funciona bien para nosotros. Las otras respuestas estaban llegando a todo esto.

La premisa básica es que las enumeraciones no se pueden heredar, pero las clases sí. Entonces...

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

Luego, para "heredar" las enumeraciones en otro proyecto de nivel superior ...

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

Esto tiene tres ventajas reales ...

  1. Las definiciones de enumeración son automáticamente las mismas en ambos proyectos, por definición.
  2. Cualquier cambio en las definiciones de enumeración se repite automáticamente en la segunda sin tener que realizar modificaciones en la segunda clase.
  3. Las enumeraciones se basan en el mismo código, por lo que los valores se pueden comparar fácilmente (con algunas advertencias).

Para hacer referencia a las enumeraciones en el primer proyecto , puede usar el prefijo de la clase: BaseEnums.StatusType.Pending o agregar un "uso de BaseEnums estáticos"; declaración a sus usos.

Sin embargo, en el segundo proyecto al tratar con la clase heredada, no pude obtener el "uso de static ..." enfoque funcionara, por lo que todas las referencias a las "enumeraciones heredadas" irían precedidas de la clase, por ejemplo, SubEnums.StatusType.Pending . Si a alguien se le ocurre una forma de permitir que se use el enfoque de "usar estática" en el segundo proyecto, avíseme.

Estoy seguro de que esto se puede ajustar para hacerlo aún mejor, pero esto realmente funciona y he usado este enfoque en proyectos de trabajo.

Por favor vote esto si lo encuentra útil.

Thomas Phaneuf
fuente
2

También quería sobrecargar Enums y creé una mezcla de la respuesta de 'Seven' en esta página y la respuesta de 'Merlyn Morgan-Graham' en una publicación duplicada de esto , más un par de mejoras.
Principales ventajas de mi solución sobre las demás:

  • incremento automático del valor int subyacente
  • nomenclatura automática

Esta es una solución lista para usar y se puede insertar directamente en su proyecto. Está diseñado para mis necesidades, por lo que si no le gustan algunas partes, simplemente reemplácelas con su propio código.

Primero, está la clase base de la CEnumque todas las enumeraciones personalizadas deberían heredar. Tiene la funcionalidad básica, similar 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;
    }
  }
}

En segundo lugar, aquí hay 2 clases Enum derivadas. Todas las clases derivadas necesitan algunos métodos básicos para funcionar como se espera. Siempre es el mismo código repetitivo; Todavía no he encontrado una manera de externalizarlo a la clase base. El código del primer nivel de herencia difiere ligeramente de todos los niveles posteriores.

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

Las clases se han probado con éxito con el siguiente código:

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
fuente
1

Las enumeraciones no son clases reales, incluso si lo parecen. Internamente, se tratan como su tipo subyacente (por defecto Int32). Por lo tanto, solo puede hacer esto "copiando" valores individuales de una enumeración a otra y convirtiéndolos en su número entero para compararlos para la igualdad.

Lucero
fuente
1

Las enumeraciones no pueden derivarse de otras enumeraciones, sino solo de int, uint, short, ushort, long, ulong, byte y sbyte.

Como dijo Pascal, puede usar los valores o constantes de otra enumeración para inicializar un valor de enumeración, pero eso es todo.

Jeroen Landheer
fuente
8
Es un nombre poco apropiado debido a la sintaxis de C #, pero los enum no pueden heredar de int, uint, etc ... En el fondo todavía heredan de System.Enum. Es solo que el miembro que representa la enumeración se escribe en int, uint, etc ...
JaredPar
@JaredPar. Cuando un enum se deriva de un uint, significa que sus valores son todos uint, etc. Por defecto, un enum hereda int. (Eche un vistazo a la especificación de C #, enum SomeEnum: uint {...} realmente funciona.)
Jeroen Landheer
44
En realidad no. Hereda System.enum. Como se publicó anteriormente y más a menudo aquí, lo que cree que es herencia es solo una ambigüedad de lenguaje en csharp.
TomTom
1

Otra posible solución:

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
fuente
1

Esto no es posible (como ya mencionó @JaredPar). Tratar de poner la lógica para solucionar esto es una mala práctica. En caso de que tenga un base classque tenga un enum, debe enumerar todos los posibles enum-valuesallí, y la implementación de la clase debería funcionar con los valores que conoce.

Por ejemplo, supongamos que tiene una clase base BaseCatalogy tiene un enum ProductFormats( Digital, Physical). Entonces puede tener un MusicCatalogo BookCatalogque podría contener ambos Digitaly Physicalproductos, pero si la clase es ClothingCatalog, solo debería contener Physicalproductos.

Jaider
fuente
1

Me doy cuenta de que llego un poco tarde a esta fiesta, pero aquí están mis dos centavos.

Todos tenemos claro que la herencia de Enum no es compatible con el marco. Se han sugerido algunas soluciones muy interesantes en este hilo, pero ninguna de ellas se sentía exactamente como lo que estaba buscando, así que tuve que intentarlo yo mismo.

Presentación: ObjectEnum

Puede consultar el código y la documentación aquí: https://github.com/dimi3tron/ObjectEnum .

Y el paquete aquí: https://www.nuget.org/packages/ObjectEnum

O simplemente instalarlo: Install-Package ObjectEnum

En resumen, ObjectEnum<TEnum>actúa como una envoltura para cualquier enumeración. Al anular GetDefinedValues ​​() en las subclases, se puede especificar qué valores de enumeración son válidos para esta clase específica.

Se han agregado varias sobrecargas de operadores para que una ObjectEnum<TEnum>instancia se comporte como si fuera una instancia de la enumeración subyacente, teniendo en cuenta las restricciones de valor definidas. Esto significa que puede comparar fácilmente la instancia con un valor int o enum, y así usarlo en un caso de cambio o cualquier otro condicional.

Me gustaría referirme al repositorio de github mencionado anteriormente para ver ejemplos e información adicional.

Espero que encuentres esto útil. Siéntase libre de comentar o abrir un problema en github para más pensamientos o comentarios.

Aquí hay algunos ejemplos breves de lo que puede hacer 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;
}
Dimitri Troncquo
fuente
-8

Puede realizar la herencia en enumeración, sin embargo, se limita solo a los siguientes tipos. int, uint, byte, sbyte, corto, ushort, largo, ulong

P.ej

public enum Car:int{
Toyota,
Benz,
}
Sriwantha Attanayake
fuente
2
Creo que la OP estaba pidiendo a heredar una enumeración de los otros, no sólo de un tipo numérico de base (que todas las enumeraciones que en C #, ya sea implícita o explícitamente.)
reirab