¿Cuál es la mejor manera de localizar la enumeración de las descripciones en .neta?

(Ver Agregar descripciones a las constantes de enumeración para enum descripción ejemplo)

Idealmente me gustaría algo que utiliza ResourceManager y los archivos de recursos de manera que se adapte a su manera de otras áreas de la aplicación están localizados.

InformationsquelleAutor Ryan | 2009-02-20

8 Comentarios

  1. 25

    Esto es lo que me terminó de ir con el, no veo el valor en la adición de un atributo personalizado de la clase para mantener un recurso clave y, a continuación, buscar en los archivos de recursos – ¿por qué no usar simplemente el enumeraciones typename + valor como un recurso clave?

    using System;
    using System.Resources;
    using System.Reflection;
    
    public class MyClass
    {
      enum SomeEnum {Small,Large};
    
      private ResourceManager _resources = new ResourceManager("MyClass.myResources",
                              System.Reflection.Assembly.GetExecutingAssembly());    
    
      public string EnumDescription(Enum enumerator)
      {     
        string rk = String.Format("{0}.{1}",enumerator.GetType(),enumerator);
        string localizedDescription = _resources.GetString(rk);
    
        if (localizedDescription == null)
           {
           //A localized string was not found so you can either just return
           //the enums value - most likely readable and a good fallback.
           return enumerator.ToString();
    
           //Or you can return the full resourceKey which will be helpful when
           //editing the resource files(e.g. MyClass+SomeEnum.Small) 
           //return resourceKey;
           }
        else
           return localizedDescription;
        }
    
    
      void SomeRoutine()
      {
        //Looks in resource file for a string matching the key
        //"MyClass+SomeEnum.Large"
        string s1 = EnumDescription(SomeEnum.Large);       
      }
    }
    • una Enumeración no es un enumerador es? Es un tipo enumerado, pero un enumerador es algo muy diferente creo…
    • El uso de C# 3.5 se puede hacer que el método de un método de extensión, de modo que usted puede utilizar SomeEnum.De gran tamaño.EnumDescription();
    • Tropecé con esta pregunta cuando busque otro problema. Yo sólo recordar que el uso de tipo y los nombres de los miembros hace que la aplicación sea más difícil de ocultar (se debe excluir el sensible declaración de que el proceso).
    • ¿Cómo puedo adaptar este código para utilizarlo en el Enum.GetValues(typeof(SomeEnum))? Me gustaría ser capaz de utilizar mi enumeraciones como origen de datos
  2. 23

    Mi solución, utilizando el lenguaje descripción atributo:

    public class LocalizedEnumAttribute : DescriptionAttribute
    {
        private PropertyInfo _nameProperty;
        private Type _resourceType;
    
        public LocalizedEnumAttribute(string displayNameKey)
            : base(displayNameKey)
        {
    
        }
    
        public Type NameResourceType
        {
            get
            {
                return _resourceType;
            }
            set
            {
                _resourceType = value;
    
                _nameProperty = _resourceType.GetProperty(this.Description, BindingFlags.Static | BindingFlags.Public);
            }
        }
    
        public override string Description
        {
            get
            {
                //check if nameProperty is null and return original display name value
                if (_nameProperty == null)
                {
                    return base.Description;
                }
    
                return (string)_nameProperty.GetValue(_nameProperty.DeclaringType, null);
            }
        }
    }
    
    public static class EnumExtender
    {
        public static string GetLocalizedDescription(this Enum @enum)
        {
            if (@enum == null)
                return null;
    
            string description = @enum.ToString();
    
            FieldInfo fieldInfo = @enum.GetType().GetField(description);
            DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
    
            if (attributes.Any())
                return attributes[0].Description;
    
            return description;
        }
    }

    La declaración Enum

    public enum MyEnum
    {
        [LocalizedEnum("ResourceName", NameResourceType = typeof(ResourceType))]
        Test = 0
    }

    A continuación, llamar a MyEnumInstance.GetLocalizedDescription()

    • Necesidades BindingFlags.Pública y las necesidades de acceso de la base.Descripción dentro de NameResourceType.conjunto. Ver mi respuesta para las banderas de la enumeración de apoyo.
    • Esto parece mucho más reutilizable para mí entonces la otra solución. Gracias
    • He tenido que cambiar de NameResourceType a typeof(Resource) para conseguir este trabajo. Gracias!
  3. 8

    hay una solución fácil:
    uso LocalizedDescription atributo para pasar un recurso clave.

        [Serializable]
        public class LocalizableDescriptionAttribute:DescriptionAttribute
        {
            public LocalizableDescriptionAttribute(string resourceKey)
                :base(Resources.ResourceManager.GetString(resourceKey))
            { }
    
        }
    • No estoy seguro de lo que esto te lleva sobre el uso de las enumeraciones nombre completo del tipo (espacio de nombres.enumname.valor) como el resourcekey como. Parece un extra de paso innecesario (el uso de la reflexión para obtener el LocalizableDescriptionAttribute) a través de sólo ir a la clase resourceManager – ¿qué me estoy perdiendo?
    • Creo que tenemos un malentendido. Puedo usar mi atributo para localizar los valores enum descripción. Supongo que estás hablando de la localización de las enumeraciones, pero no sus valores.
    • No se puede decorar el valor de enumeración con la Descripción de atributos y pasar un recurso clave.
    • Nada de eso – quiero salir de la enumeración de los valores de la misma, sólo localizar una descripción. Mi propia respuesta a continuación puede hacer mi comentario más clara. (Por CIERTO, – ignorar dónde he dicho reflexión, debería haber dicho LocalizableDescriptionAttribute.GetCustomAttribute)
  4. 3

    Una manera en que yo lo hice una vez, fue para agregar una extensión del método en el mismo espacio de nombres como una enumeración, que devuelve una cadena. En mi caso solo fue codificado, pero no habría ningún problema, llegar a ellos desde un archivo de recursos.

        public static string Describe(this SomeEnum e)
        {
            switch(e)
            {
                SomeEnum.A:
                    return "Some text from resourcefile";
                SomeEnum.B:
                    return "Some other text from resourcefile";
                ...:
                    return ...;
            }
        }

    Tal vez no un extremadamente suave o de lujo solución, pero funciona =)

    • + 1 para el uso de un método de extensión…aunque yo prefiero utilizar la enumeración de tipo completo nombre como el recurso clave (ver Ryans respuesta)
    • Sí, eso podría ser una muy buena forma alternativa de llegar a las cuerdas.
  5. 1

    Reemplazar @nairik del método con la siguiente para agregar el soporte para indicadores de las enumeraciones.

    public static string GetLocalizedDescription(this Enum @enum)
    {
        if ( @enum == null )
            return null;
    
        StringBuilder sbRet = new StringBuilder();
    
        string description = @enum.ToString();
    
        var fields = description.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
    
        foreach ( var field in fields )
        {
            FieldInfo fieldInfo = @enum.GetType().GetField(field);
            DescriptionAttribute[] attributes = ( DescriptionAttribute[] )fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
    
            if ( attributes.Any() )
                sbRet.AppendFormat("{0}, ", attributes[0].Description);
            else
                sbRet.AppendFormat("{0}, ", field);
        }
    
        if ( sbRet.Length > 2 )
            sbRet.Remove(sbRet.Length - 2, 2);
    
        return sbRet.ToString();
    }

    y reemplazar NameResourceType en el atributo:

    public Type NameResourceType
    {
        get
        {
            return _resourceType;
        }
        set
        {
            _resourceType = value;
    
            _nameProperty = _resourceType.GetProperty(base.Description, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
        }
    }
  6. 0

    Ver mi tabla de ejemplo en esta pregunta:

    Localización/I18n de datos de base de datos en LINQ to SQL

    El estado de la tabla de tipo de mapas para los valores de Enumeración. El beneficio real aquí es que usted puede tener la localización en sus informes y a través de sus aplicaciones, y especificar externo Identificadores para la integración con 3ras partes que no quiere que sus valores internos, etc. Se desacopla de la enumeración descripción de su valor.

    • Buen método para db centrado en las aplicaciones, pero realmente excesivo para mis necesidades.
  7. 0

    No puede tener varios Sistema.ComponentModel.DescriptionAttribute aplicada (por lo que la opción está fuera).

    Para agregar un nivel de indirección, la descripción contiene el nombre de un recurso y, a continuación, utilizar la localización de apoyo en recursos. Claramente a los usuarios de la enumeración se necesitará llamar a su método auxiliar para hacer esto.

    • Esto es lo Valentin Vasiliev propone, pero sin la necesidad de utilizar un método helper – la misma observación se aplica también.

Dejar respuesta

Please enter your comment!
Please enter your name here