Enum “Herencia”

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 nombre de nivel medio que “hereda” el bajo nivel de enumeración.

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 tomar el lugar del consumo enum que proporcionará una capa de abstracción para la enumeración, pero aún así dejar 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 conste en las clases es que el enum de bajo nivel es necesario por un servicio que debo consumir. Me han dado los WSDL y los XSD, que definen la estructura como una enumeración. El servicio no puede ser cambiado.

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

Consulte la sección 8.5.2 de la especificación CLI para obtener más información. Información relevante de la especificación

  • Todas las enumeraciones deben derivarse de System.Enum
  • Debido a lo anterior, todas las enumeraciones son tipos de valor y, por lo tanto, selladas

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 puedes usar estas clases de manera similar a cuando eran enumeraciones:

 int i = Consume.B; 

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

Si asigna los mismos valores int a las constantes definidas en la enumeración existente, entonces 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; 

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(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 enteros en lugar de enum, pero ese tipo también apesta.

El retorno del método de extensión debe escribirlo en el tipo T.

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

Deberí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 enums disponibles. Esto proporciona un comportamiento casi enumático. La única advertencia es que estas constantes no se pueden usar dentro de una statement de cambio.

 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) { /* ... */ } // ... } 

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

Lo mejor que podrías 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()); } } 

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

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

 public class BaseAnimal : IEquatable { 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) { } 

Esto es lo que hice. Lo que he hecho diferente es usar el mismo nombre y la new palabra clave en la enum “consumidora”. Como el nombre de la enum es el mismo, puedes usarlo sin pensar y será correcto. Además, obtienes intellisense. Solo debe tener cuidado manualmente al configurarlo para que los valores se copien desde la base y mantenerlos sincronizados. Puedes ayudar con los comentarios del código. Esta es otra razón por la cual en la base de datos al almacenar valores enum , siempre almaceno la cadena, no el valor. Porque si usa valores enteros en aumento 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 } } 

Los enums no son clases reales, incluso si se 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 transfiriéndolos a su número entero para compararlos por igualdad.

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

Como dijo Pascal, puedes usar los valores o constantes de otras enum para inicializar un valor enum, pero eso es todo.

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

Esto no es posible (como @JaredPar ya se mencionó). Tratar de poner la lógica a trabajar en esto es una mala práctica. En caso de que tenga una base class que tenga una enum , debe listar todos enum-values posibles allí, y la implementación de la clase debería funcionar con los valores que conoce.

Por ejemplo, BaseCatalog que tiene un BaseCatalog clase base, y tiene un enum ProductFormats ( Digital , Physical ). Entonces puede tener un BookCatalog o BookCatalog que pueda contener productos Digital y Physical , pero si la clase es ClothingCatalog , solo debe contener productos Physical .

También quería sobrecargar Enums y creé una combinación de la respuesta de ‘Siete’ 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
  • nombres automáticos

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

En primer lugar, está el CEnum clase base del que deben heredar todas las enumeraciones personalizadas. Tiene la funcionalidad básica, similar al tipo .um Enum :

 public class CEnum { protected static readonly int msc_iUpdateNames = int.MinValue; protected static int ms_iAutoValue = -1; protected static List ms_listiValue = new List(); 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 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 la 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 ms_listoValue = new List(); 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 listoValue = new List (); listoValue.AddRange (ms_listoValue); return listoValue.ToArray (); } } public class CEnumResultClassCommon : CEnumResult { private static List ms_listoValue = new List(); 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 listoValue = new List (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 } 

Puede realizar la herencia en enum, sin embargo, está limitado solo a los siguientes tipos. int, uint, byte, sbyte, corto, ushort, largo, ulong

P.ej

 public enum Car:int{ Toyota, Benz, }