switch - return enum c#
Enum "Herencia" (13)
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 tomar el lugar del consumo de enumeración que proporcione una capa de abstracción para la enumeración, pero que permita que una instancia de esa clase acceda a la enumeración.
¿Pensamientos?
EDITAR: Una de las razones por las que no he cambiado esto a consts en las clases es que la enumeración de bajo nivel es necesaria para un servicio que debo consumir. Me dieron los WSDL y los XSD, que definen la estructura como una enumeración. El servicio no puede ser cambiado.
Esto es lo que hice. Lo que he hecho de manera diferente es usar el mismo nombre y la new
palabra clave en la enum
"consumidora". Ya que el nombre de la enum
es el mismo, puedes usarlo sin pensar y será correcto. Además obtienes intellisense. Solo tiene que tener cuidado manualmente al configurar que los valores se copian desde la base y mantenerlos sincronizados. Usted puede ayudar a que junto con los comentarios de código. Esta es otra razón por la que en la base de datos al almacenar valores enum
, siempre almaceno la cadena, no el valor. Porque si está utilizando valores enteros crecientes asignados automáticamente, esos 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
}
}
Esto no es posible (como ya se mencionó @JaredPar). Tratar de poner en práctica la lógica es una mala práctica. En caso de que tenga una base class
que tenga una enum
, debe enumerar todos enum-values
posibles allí, y la implementación de la clase debería funcionar con los valores que conoce.
Por ejemplo, se supone que tiene una clase base BaseCatalog
, y tiene una enum ProductFormats
( Digital
, Physical
). Luego puede tener un BookCatalog
o BookCatalog
que podría contener productos Digital
y Physical
, pero si la clase es ClothingCatalog
, solo debería contener productos Physical
.
Esto no es posible. Enums no pueden heredar de otros enums. De hecho, todas las enumeraciones deben heredar realmente de System.Enum
. C # permite que la sintaxis cambie la representación subyacente de los valores de enumeración que se parecen a la 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 conocer 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, selladas
Ignorando el hecho de que base es una palabra reservada, no puede hacer herencia de enumeración.
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), podría asignar el valor de una instancia de un tipo a otro que se emitirá. No es ideal pero funciona.
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! = Consumir.A
Aunque 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 Consumo ...
También puede emitir los valores de las enumeraciones como ints, y compararlos como ints en lugar de enum, pero eso también apesta.
El método de extensión return debe escribir cast it type T.
Las enumeraciones no se pueden generar de otras enumeraciones, sino solo de int, uint, short, ushort, long, ulong, byte y sbyte.
Como dijo Pascal, puede usar otros valores o constantes de enumeración para inicializar un valor de enumeración, pero eso es todo.
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 asignándolos a su número entero para compararlos en busca de igualdad.
Las soluciones anteriores que usan clases con constantes int carecen de seguridad de tipo. Es decir, podrías inventar nuevos valores que en realidad no están 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, hay una solución basada en clase de los viejos tiempos de Java, cuando no había enumerados disponibles. Esto proporciona un comportamiento casi en forma de enumeración. 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) { /* ... */ }
// ...
}
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
Puede realizar la herencia en la enumeración, sin embargo, se limita a los siguientes tipos solamente. int, uint, byte, sbyte, short, ushort, long, ulong
P.ej
public enum Car:int{
Toyota,
Benz,
}
Puedes lograr lo que quieras 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 forma similar a como eran enumras:
int i = Consume.B;
Actualización (después de su 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;
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)
{
}
También quería sobrecargar a Enums y creé una combinación de share y la respuesta de ''Merlyn Morgan-Graham'' en una publicación duplicada de este , más un par de mejoras.
Principales ventajas de mi solución sobre las demás:
- Incremento automático del valor int subyacente.
- nombramiento automático
Esta es una solución lista para usar y puede insertarse 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 CEnum
que todos los enumerados personalizados deben heredar. Tiene la funcionalidad básica, similar al tipo .net Enum
:
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 han sido probadas 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
}