type - enum.getvalues c#




Representación de cadena de un Enum (20)

Cómo resolví esto como un método de extensión:

using System.ComponentModel;
public static string GetDescription(this Enum value)
{
    var descriptionAttribute = (DescriptionAttribute)value.GetType()
        .GetField(value.ToString())
        .GetCustomAttributes(false)
        .Where(a => a is DescriptionAttribute)
        .FirstOrDefault();

    return descriptionAttribute != null ? descriptionAttribute.Description : value.ToString();
}

Enumerar

public enum OrderType
{
    None = 0,
    [Description("New Card")]
    NewCard = 1,
    [Description("Reload")]
    Refill = 2
}

Uso (donde o.OrderType es una propiedad con el mismo nombre que la enumeración):

o.OrderType.GetDescription()

Lo que me da una cadena de "Nueva tarjeta" o "Recargar" en lugar del valor de enumeración real NewCard y Recarga.

Tengo la siguiente enumeración:

public enum AuthenticationMethod
{
    FORMS = 1,
    WINDOWSAUTHENTICATION = 2,
    SINGLESIGNON = 3
}

Sin embargo, el problema es que necesito la palabra "FORMAS" cuando pido AuthenticationMethod.FORMS y no el ID 1.

He encontrado la siguiente solución para este problema ( link ):

Primero necesito crear un atributo personalizado llamado "StringValue":

public class StringValue : System.Attribute
{
    private readonly string _value;

    public StringValue(string value)
    {
        _value = value;
    }

    public string Value
    {
        get { return _value; }
    }

}

Entonces puedo agregar este atributo a mi enumerador:

public enum AuthenticationMethod
{
    [StringValue("FORMS")]
    FORMS = 1,
    [StringValue("WINDOWS")]
    WINDOWSAUTHENTICATION = 2,
    [StringValue("SSO")]
    SINGLESIGNON = 3
}

Y, por supuesto, necesito algo para recuperar ese StringValue:

public static class StringEnum
{
    public static string GetStringValue(Enum value)
    {
        string output = null;
        Type type = value.GetType();

        //Check first in our cached results...

        //Look for our 'StringValueAttribute' 

        //in the field's custom attributes

        FieldInfo fi = type.GetField(value.ToString());
        StringValue[] attrs =
           fi.GetCustomAttributes(typeof(StringValue),
                                   false) as StringValue[];
        if (attrs.Length > 0)
        {
            output = attrs[0].Value;
        }

        return output;
    }
}

Bien, ahora tengo las herramientas para obtener un valor de cadena para un enumerador. Entonces puedo usarlo así:

string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);

Bueno, ahora todo esto funciona como un encanto, pero me parece mucho trabajo. Me preguntaba si hay una mejor solución para esto.

También probé algo con un diccionario y propiedades estáticas, pero eso tampoco fue mejor.


Como la mayoría de ustedes, me gustó mucho la respuesta seleccionada de Jakub Šturc , pero también odio copiar y pegar el código, y trato de hacerlo lo menos posible.

Así que decidí que quería una clase EnumBase de la que se hereda / incorpore la mayor parte de la funcionalidad, lo que me permite centrarme en el contenido en lugar del comportamiento.

El problema principal con este enfoque se basa en el hecho de que, aunque los valores de Enum son instancias seguras para el tipo, la interacción es con la implementación estática del tipo de Clase de Enum. Así que con un poco de magia genérica, creo que finalmente obtuve la combinación correcta. Espero que alguien encuentre esto tan útil como yo lo hice.

Comenzaré con el ejemplo de Jakub, pero usando herencia y genéricos:

public sealed class AuthenticationMethod : EnumBase<AuthenticationMethod, int>
{
    public static readonly AuthenticationMethod FORMS =
        new AuthenticationMethod(1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION =
        new AuthenticationMethod(2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON =
        new AuthenticationMethod(3, "SSN");

    private AuthenticationMethod(int Value, String Name)
        : base( Value, Name ) { }
    public new static IEnumerable<AuthenticationMethod> All
    { get { return EnumBase<AuthenticationMethod, int>.All; } }
    public static explicit operator AuthenticationMethod(string str)
    { return Parse(str); }
}

Y aquí está la clase base:

using System;
using System.Collections.Generic;
using System.Linq; // for the .AsEnumerable() method call

// E is the derived type-safe-enum class
// - this allows all static members to be truly unique to the specific
//   derived class
public class EnumBase<E, T> where E: EnumBase<E, T>
{
    #region Instance code
    public T Value { get; private set; }
    public string Name { get; private set; }

    protected EnumBase(T EnumValue, string Name)
    {
        Value = EnumValue;
        this.Name = Name;
        mapping.Add(Name, this);
    }

    public override string ToString() { return Name; }
    #endregion

    #region Static tools
    static private readonly Dictionary<string, EnumBase<E, T>> mapping;
    static EnumBase() { mapping = new Dictionary<string, EnumBase<E, T>>(); }
    protected static E Parse(string name)
    {
        EnumBase<E, T> result;
        if (mapping.TryGetValue(name, out result))
        {
            return (E)result;
        }

        throw new InvalidCastException();
    }
    // This is protected to force the child class to expose it's own static
    // method.
    // By recreating this static method at the derived class, static
    // initialization will be explicit, promising the mapping dictionary
    // will never be empty when this method is called.
    protected static IEnumerable<E> All
    { get { return mapping.Values.AsEnumerable().Cast<E>(); } }
    #endregion
}

Desafortunadamente, la reflexión para obtener atributos en enumeraciones es bastante lenta:

Vea esta pregunta: ¿ Alguien sabe una forma rápida de obtener atributos personalizados en un valor de enumeración?

El .ToString() es bastante lento en las enumeraciones también.

Puedes escribir métodos de extensión para enumeraciones aunque:

public static string GetName( this MyEnum input ) {
    switch ( input ) {
        case MyEnum.WINDOWSAUTHENTICATION:
            return "Windows";
        //and so on
    }
}

Esto no es excelente, pero será rápido y no requerirá la reflexión para los atributos o el nombre del campo.

Actualización C # 6

Si puede usar C # 6, entonces el nuevo operador nameof funciona para enumeraciones, por lo que nameof(MyEnum.WINDOWSAUTHENTICATION) se convertirá a "WINDOWSAUTHENTICATION" en el momento de la compilación , por lo que es la forma más rápida de obtener nombres de enumeración.

Tenga en cuenta que esto convertirá la enumeración explícita en una constante en línea, por lo que no funciona para las enumeraciones que tiene en una variable. Asi que:

nameof(AuthenticationMethod.FORMS) == "FORMS"

Pero...

var myMethod = AuthenticationMethod.FORMS;
nameof(myMethod) == "myMethod"

En su pregunta nunca dijo que realmente necesita el valor numérico de la enumeración en cualquier lugar.

Si no lo hace y solo necesita una enumeración de tipo cadena (que no es un tipo integral, por lo que no puede ser una base de enumeración), aquí tiene una forma:

    static class AuthenticationMethod
    {
        public static readonly string
            FORMS = "Forms",
            WINDOWSAUTHENTICATION = "WindowsAuthentication";
    }

puede utilizar la misma sintaxis que enum para hacer referencia a ella

if (bla == AuthenticationMethod.FORMS)

Será un poco más lento que con los valores numéricos (comparando cadenas en lugar de números), pero en el lado positivo no está utilizando la reflexión (lento) para acceder a la cadena.


Mi variante

public struct Colors
{
    private String current;

    private static string red = "#ff0000";
    private static string green = "#00ff00";
    private static string blue = "#0000ff";

    private static IList<String> possibleColors; 

    public static Colors Red { get { return (Colors) red; } }
    public static Colors Green { get { return (Colors) green; } }
    public static Colors Blue { get { return (Colors) blue; } }

    static Colors()
    {
        possibleColors = new List<string>() {red, green, blue};
    }

    public static explicit operator String(Colors value)
    {
        return value.current;
    }

    public static explicit operator Colors(String value)
    {
        if (!possibleColors.Contains(value))
        {
            throw new InvalidCastException();
        }

        Colors color = new Colors();
        color.current = value;
        return color;
    }

    public static bool operator ==(Colors left, Colors right)
    {
        return left.current == right.current;
    }

    public static bool operator !=(Colors left, Colors right)
    {
        return left.current != right.current;
    }

    public bool Equals(Colors other)
    {
        return Equals(other.current, current);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (obj.GetType() != typeof(Colors)) return false;
        return Equals((Colors)obj);
    }

    public override int GetHashCode()
    {
        return (current != null ? current.GetHashCode() : 0);
    }

    public override string ToString()
    {
        return current;
    }
}

El código parece un poco feo, pero los usos de esta estructura son bastante presentativos.

Colors color1 = Colors.Red;
Console.WriteLine(color1); // #ff0000

Colors color2 = (Colors) "#00ff00";
Console.WriteLine(color2); // #00ff00

// Colors color3 = "#0000ff"; // Compilation error
// String color4 = Colors.Red; // Compilation error

Colors color5 = (Colors)"#ff0000";
Console.WriteLine(color1 == color5); // True

Colors color6 = (Colors)"#00ff00";
Console.WriteLine(color1 == color6); // False

Además, creo que, si se requiere una gran cantidad de tales enumeraciones, se puede usar la generación de código (por ejemplo, T4).


Pruebe el type-safe-enum patrón de type-safe-enum .

public sealed class AuthenticationMethod {

    private readonly String name;
    private readonly int value;

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (3, "SSN");        

    private AuthenticationMethod(int value, String name){
        this.name = name;
        this.value = value;
    }

    public override String ToString(){
        return name;
    }

}

Actualización de tipo explícita (o implícita) la conversión se puede hacer por

  • añadiendo campo estático con mapeo

    private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
    
    • nb Para que la inicialización de los campos del "miembro de enumeración" no arroje una NullReferenceException al llamar al constructor de la instancia, asegúrese de colocar el campo Diccionario antes de los campos de "miembro de la enumeración" en su clase. Esto se debe a que los inicializadores de campo estático se llaman en orden de declaración, y antes del constructor estático, creando la situación extraña y necesaria pero confusa de que se puede llamar al constructor de instancia antes de que se hayan inicializado todos los campos estáticos, y antes de que se llame al constructor estático.
  • llenando este mapeo en el constructor de instancia

    instance[name] = this;
    
  • y agregar operador de conversión de tipo definido por el usuario

    public static explicit operator AuthenticationMethod(string str)
    {
        AuthenticationMethod result;
        if (instance.TryGetValue(str, out result))
            return result;
        else
            throw new InvalidCastException();
    }
    

Quería publicar esto como un comentario a la publicación citada a continuación, pero no pude porque no tengo suficiente reputación, así que por favor, no voten a la baja. El código contenía un error y quería señalarlo a las personas que intentaban usar esta solución:

[TypeConverter(typeof(CustomEnumTypeConverter(typeof(MyEnum))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,
  // This will be exposed exactly.
  Exact
}

debiera ser

[TypeConverter(typeof(CustomEnumTypeConverter<MyEnum>))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,

  // This will be exposed exactly.
  Exact
}

¡Brillante!


Realmente me gusta la respuesta de Jakub Šturc, pero su defecto es que no se puede usar con una declaración de cambio de caso. Aquí hay una versión ligeramente modificada de su respuesta que puede usarse con una declaración de cambio:

public sealed class AuthenticationMethod
{
    #region This code never needs to change.
    private readonly string _name;
    public readonly Values Value;

    private AuthenticationMethod(Values value, String name){
        this._name = name;
        this.Value = value;
    }

    public override String ToString(){
        return _name;
    }
    #endregion

    public enum Values
    {
        Forms = 1,
        Windows = 2,
        SSN = 3
    }

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (Values.Forms, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (Values.Windows, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (Values.SSN, "SSN");
}

Entonces, obtienes todos los beneficios de la respuesta de Jakub Šturc, y además podemos usarlo con una declaración de cambio como la siguiente:

var authenticationMethodVariable = AuthenticationMethod.FORMS;  // Set the "enum" value we want to use.
var methodName = authenticationMethodVariable.ToString();       // Get the user-friendly "name" of the "enum" value.

// Perform logic based on which "enum" value was chosen.
switch (authenticationMethodVariable.Value)
{
    case authenticationMethodVariable.Values.Forms: // Do something
        break;
    case authenticationMethodVariable.Values.Windows: // Do something
        break;
    case authenticationMethodVariable.Values.SSN: // Do something
        break;      
}

Solo usa el método ToString()

public enum any{Tomato=0,Melon,Watermelon}

Para referenciar la cadena de Tomato , solo usa

any.Tomato.ToString();

Una solución muy simple para esto con .Net 4.0 y superior. No se necesita ningún otro código.

public enum MyStatus
{
    Active = 1,
    Archived = 2
}

Para obtener la cadena sobre solo usar:

MyStatus.Active.ToString("f");

o

MyStatus.Archived.ToString("f");`

El valor será "Activo" o "Archivado".

Para ver los diferentes formatos de cadena (la "f" de arriba) al llamar a Enum.ToString consulte esta página de cadenas de formato de enumeración .


Utilizo una combinación de varias de las sugerencias anteriores, combinadas con algo de almacenamiento en caché. Ahora, obtuve la idea de un código que encontré en algún lugar de la red, pero tampoco recuerdo dónde lo obtuve ni lo encontré. Entonces, si alguien encuentra algo similar, por favor comente con la atribución.

De todos modos, el uso involucra a los convertidores de tipo, por lo que si está vinculado a la interfaz de usuario, 'simplemente funciona'. Puede extenderse con el patrón de Jakub para la búsqueda rápida de códigos al inicializar el convertidor de tipos en los métodos estáticos.

El uso base se vería así

[TypeConverter(typeof(CustomEnumTypeConverter<MyEnum>))]
public enum MyEnum
{
    // The custom type converter will use the description attribute
    [Description("A custom description")]
    ValueWithCustomDescription,

   // This will be exposed exactly.
   Exact
}

El código para el convertidor de tipo de enumeración personalizado sigue:

public class CustomEnumTypeConverter<T> : EnumConverter
    where T : struct
{
    private static readonly Dictionary<T,string> s_toString = 
      new Dictionary<T, string>();

    private static readonly Dictionary<string, T> s_toValue = 
      new Dictionary<string, T>();

    private static bool s_isInitialized;

    static CustomEnumTypeConverter()
    {
        System.Diagnostics.Debug.Assert(typeof(T).IsEnum,
          "The custom enum class must be used with an enum type.");
    }

    public CustomEnumTypeConverter() : base(typeof(T))
    {
        if (!s_isInitialized)
        {
            Initialize();
            s_isInitialized = true;
        }
    }

    protected void Initialize()
    {
        foreach (T item in Enum.GetValues(typeof(T)))
        {
            string description = GetDescription(item);
            s_toString[item] = description;
            s_toValue[description] = item;
        }
    }

    private static string GetDescription(T optionValue)
    {
        var optionDescription = optionValue.ToString();
        var optionInfo = typeof(T).GetField(optionDescription);
        if (Attribute.IsDefined(optionInfo, typeof(DescriptionAttribute)))
        {
            var attribute = 
              (DescriptionAttribute)Attribute.
                 GetCustomAttribute(optionInfo, typeof(DescriptionAttribute));
            return attribute.Description;
        }
        return optionDescription;
    }

    public override object ConvertTo(ITypeDescriptorContext context, 
       System.Globalization.CultureInfo culture, 
       object value, Type destinationType)
    {
        var optionValue = (T)value;

        if (destinationType == typeof(string) && 
            s_toString.ContainsKey(optionValue))
        {
            return s_toString[optionValue];
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, 
       System.Globalization.CultureInfo culture, object value)
    {
        var stringValue = value as string;

        if (!string.IsNullOrEmpty(stringValue) && s_toValue.ContainsKey(stringValue))
        {
            return s_toValue[stringValue];
        }

        return base.ConvertFrom(context, culture, value);
    }
}

}


Yo uso un método de extensión:

public static class AttributesHelperExtension
    {
        public static string ToDescription(this Enum value)
        {
            var da = (DescriptionAttribute[])(value.GetType().GetField(value.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return da.Length > 0 ? da[0].Description : value.ToString();
        }
}

Ahora decora la enum con:

public enum AuthenticationMethod
{
    [Description("FORMS")]
    FORMS = 1,
    [Description("WINDOWSAUTHENTICATION")]
    WINDOWSAUTHENTICATION = 2,
    [Description("SINGLESIGNON ")]
    SINGLESIGNON = 3
}

Cuando usted llama

AuthenticationMethod.FORMS.ToDescription() obtendrá "FORMS" .


Estoy de acuerdo con Keith, pero no puedo votar (todavía).

Utilizo un método estático y una declaración swith para devolver exactamente lo que quiero. En la base de datos almaceno tinyint y mi código solo usa la enumeración real, por lo que las cadenas son para los requisitos de la interfaz de usuario. Después de numerosas pruebas, esto dio como resultado el mejor rendimiento y el mayor control sobre la salida.

public static string ToSimpleString(this enum)
{
     switch (enum)
     {
         case ComplexForms:
             return "ComplexForms";
             break;
     }
}

public static string ToFormattedString(this enum)
{
     switch (enum)
     {
         case ComplexForms:
             return "Complex Forms";
             break;
     }
}

Sin embargo, según algunas cuentas, esto conduce a una posible pesadilla de mantenimiento y algo de olor de código. Intento vigilar los enums que son largos y muchos enums, o los que cambian con frecuencia. De lo contrario, esta ha sido una gran solución para mí.


Cuando estoy en una situación como esa, propongo la solución a continuación.

Y como clase consumidora podrías tener

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyApp.Dictionaries
{
    class Greek
    {

        public static readonly string Alpha = "Alpha";
        public static readonly string Beta = "Beta";
        public static readonly string Gamma = "Gamma";
        public static readonly string Delta = "Delta";


        private static readonly BiDictionary<int, string> Dictionary = new BiDictionary<int, string>();


        static Greek() {
            Dictionary.Add(1, Alpha);
            Dictionary.Add(2, Beta);
            Dictionary.Add(3, Gamma);
            Dictionary.Add(4, Delta);
        }

        public static string getById(int id){
            return Dictionary.GetByFirst(id);
        }

        public static int getByValue(string value)
        {
            return Dictionary.GetBySecond(value);
        }

    }
}

Y utilizando un diccionario bidireccional: en base a esto ( https://.com/a/255638/986160 ), asumiendo que las claves se asociarán con valores únicos en el diccionario y similares a ( https://.com/a/255630/986160 ) pero un poco más elegante. Este diccionario también es enumerable y puede ir y venir de ints a cadenas. Además, no tienes que tener ninguna cadena en tu base de código con la excepción de esta clase.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace MyApp.Dictionaries
{

    class BiDictionary<TFirst, TSecond> : IEnumerable
    {
        IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
        IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

        public void Add(TFirst first, TSecond second)
        {
            firstToSecond.Add(first, second);
            secondToFirst.Add(second, first);
        }

        public TSecond this[TFirst first]
        {
            get { return GetByFirst(first); }
        }

        public TFirst this[TSecond second]
        {
            get { return GetBySecond(second); }
        }

        public TSecond GetByFirst(TFirst first)
        {
            return firstToSecond[first];
        }

        public TFirst GetBySecond(TSecond second)
        {
            return secondToFirst[second];
        }

        public IEnumerator GetEnumerator()
        {
            return GetFirstEnumerator();
        }

        public IEnumerator GetFirstEnumerator()
        {
            return firstToSecond.GetEnumerator();
        }

        public IEnumerator GetSecondEnumerator()
        {
            return secondToFirst.GetEnumerator();
        }
    }
}

Mi respuesta, trabajar en la respuesta de @ user29964 (que es por mucho la más simple y cercana a una Enum) es

 public class StringValue : System.Attribute
    {
        private string _value;

        public StringValue(string value)
        {
            _value = value;
        }

        public string Value
        {
            get { return _value; }
        }



        public static string GetStringValue(Enum Flagvalue)
        {
            Type type = Flagvalue.GetType();
            string[] flags = Flagvalue.ToString().Split(',').Select(x => x.Trim()).ToArray();
            List<string> values = new List<string>();

            for (int i = 0; i < flags.Length; i++)
            {

                FieldInfo fi = type.GetField(flags[i].ToString());

                StringValue[] attrs =
                   fi.GetCustomAttributes(typeof(StringValue),
                                           false) as StringValue[];
                if (attrs.Length > 0)
                {
                    values.Add(attrs[0].Value);
                }
            }
            return String.Join(",", values);

        }

uso

[Flags]
    public enum CompeteMetric
    {

        /// <summary>
        /// u
        /// </summary>
        [StringValue("u")]//Json mapping
        Basic_UniqueVisitors = 1 //Basic
             ,
        /// <summary>
        /// vi
        /// </summary>
        [StringValue("vi")]//json mapping
        Basic_Visits = 2// Basic
            ,
        /// <summary>
        /// rank
        /// </summary>
        [StringValue("rank")]//json mapping
        Basic_Rank = 4//Basic
 }

Ejemplo

        CompeteMetric metrics = CompeteMetric.Basic_Visits | CompeteMetric.Basic_Rank;
        string strmetrics = StringValue.GetStringValue(metrics);

esto devolverá "vi, rango"


Muchas respuestas geniales aquí, pero en mi caso no resolvieron lo que quería de una "enumeración de cadena", que era:

  1. Utilizable en una declaración de cambio, por ejemplo, switch (myEnum)
  2. Se puede utilizar en parámetros de función, por ejemplo, foo (tipo myEnum)
  3. Puede ser referenciado, por ejemplo, myEnum.FirstElement
  4. Puedo usar cadenas, por ejemplo, foo ("FirstElement") == foo (myEnum.FirstElement)

1,2 y 4 pueden resolverse con un C # Typedef de una cadena (ya que las cadenas son conmutables en c #)

3 pueden resolverse mediante constantes estáticas. Entonces, si tiene las mismas necesidades, este es el enfoque más simple:

public sealed class Types
{

    private readonly String name;

    private Types(String name)
    {
        this.name = name;

    }

    public override String ToString()
    {
        return name;
    }

    public static implicit operator Types(string str)
    {
        return new Types(str);

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }


    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";
    public const string Folder = "Folder";
    #endregion

}

Esto permite por ejemplo:

    public TypeArgs(Types SelectedType)
    {
        Types SelectedType = SelectedType
    }

y

public TypeObject CreateType(Types type)
    {
        switch (type)
        {

            case Types.ImageType:
              //
                break;

            case Types.DataType:
             //
                break;

        }
    }

Donde CreateType se puede llamar con una cadena o un tipo. Sin embargo, el inconveniente es que cualquier cadena es automáticamente una enumeración válida , esto podría modificarse, pero luego requeriría algún tipo de función de inicio ... ¿o posiblemente la conversión explícita interna?

Ahora bien, si un valor int era importante para ti (quizás para la velocidad de comparación), podrías usar algunas ideas de la fantástica respuesta de Jakub Šturc y hacer algo un poco loco, esta es mi prueba:

    public sealed class Types
{
    private static readonly Dictionary<string, Types> strInstance = new Dictionary<string, Types>();
    private static readonly Dictionary<int, Types> intInstance = new Dictionary<int, Types>();

    private readonly String name;
    private static int layerTypeCount = 0;
    private int value;
    private Types(String name)
    {
        this.name = name;
        value = layerTypeCount++;
        strInstance[name] = this;
        intInstance[value] = this;
    }

    public override String ToString()
    {
        return name;
    }


    public static implicit operator Types(int val)
    {
        Types result;
        if (intInstance.TryGetValue(val, out result))
            return result;
        else
            throw new InvalidCastException();
    }

    public static implicit operator Types(string str)
    {
        Types result;
        if (strInstance.TryGetValue(str, out result))
        {
            return result;
        }
        else
        {
            result = new Types(str);
            return result;
        }

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }

    public static bool operator ==(Types a, Types b)
    {
        return a.value == b.value;
    }
    public static bool operator !=(Types a, Types b)
    {
        return a.value != b.value;
    }

    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";

    #endregion

}

pero por supuesto "Types bob = 4;" no tendría sentido a menos que primero los hubieras inicializado, lo que de alguna forma anularía el punto ...

Pero en teoría, TypeA == TypeB sería más rápido ...


Para mí, el enfoque pragmático es clase dentro de clase, muestra:

public class MSEModel
{
    class WITS
    {
        public const string DATE = "5005";
        public const string TIME = "5006";
        public const string MD = "5008";
        public const string ROP = "5075";
        public const string WOB = "5073";
        public const string RPM = "7001";
... 
    }

Bueno, después de leer todo lo anterior, siento que los chicos han complicado el problema de transformar los enumeradores en cadenas. Me gustó la idea de tener atributos sobre campos enumerados, pero creo que los atributos se utilizan principalmente para metadatos, pero en su caso, creo que todo lo que necesita es algún tipo de localización.

public enum Color 
{ Red = 1, Green = 2, Blue = 3}


public static EnumUtils 
{
   public static string GetEnumResourceString(object enumValue)
    {
        Type enumType = enumValue.GetType();
        string value = Enum.GetName(enumValue.GetType(), enumValue);
        string resourceKey = String.Format("{0}_{1}", enumType.Name, value);
        string result = Resources.Enums.ResourceManager.GetString(resourceKey);
        if (string.IsNullOrEmpty(result))
        {
            result = String.Format("{0}", value);
        }
        return result;
    }
}

Ahora, si intentamos llamar al método anterior, podemos llamarlo de esta manera

public void Foo()
{
  var col = Color.Red;
  Console.WriteLine (EnumUtils.GetEnumResourceString (col));
}

Todo lo que necesita hacer es crear un archivo de recursos que contenga todos los valores del enumerador y las cadenas correspondientes

Resource Name          Resource Value
Color_Red              My String Color in Red
Color_Blue             Blueeey
Color_Green            Hulk Color

Lo que realmente es bueno es que será muy útil si necesita que su aplicación se localice, ya que todo lo que necesita hacer es crear otro archivo de recursos con su nuevo idioma. y Voe-la!


Si piensa en el problema que estamos tratando de resolver, no es una enumeración que necesitamos en absoluto. Necesitamos un objeto que permita asociar un cierto número de valores entre sí; en otras palabras, para definir una clase.

El patrón de enumeración de tipo seguro de Jakub Šturc es la mejor opción que veo aquí.

Míralo:

  • Tiene un constructor privado por lo que solo la clase en sí puede definir los valores permitidos.
  • Es una clase sellada, por lo que los valores no pueden modificarse a través de la herencia.
  • Es de tipo seguro, permitiendo que sus métodos requieran solo ese tipo.
  • No hay un impacto en el rendimiento de la reflexión incurrido al acceder a los valores.
  • Y, por último, se puede modificar para asociar más de dos campos juntos, por ejemplo, un Nombre, una Descripción y un Valor numérico.





enums