Мои перечисления могут иметь дружественные имена? [дубликат]

Второй является классическим примером Антишаблон Стрелки , Таким образом, я избежал бы его...

, Если Ваши условия являются слишком длинными, извлекают их в методы/свойства.

169
задан Default 10 April 2013 в 08:15
поделиться

11 ответов

Имена значений перечисления должны соответствовать тем же правилам именования, что и все идентификаторы в C #, поэтому только имя является правильным.

77
ответ дан 23 November 2019 в 20:49
поделиться

Если у вас есть следующее перечисление:

public enum MyEnum {
    First,
    Second,
    Third
}

Вы можете объявить методы расширения для MyEnum (как и для любого другого типа). Я только что придумал:

namespace Extension {
    public static class ExtensionMethods {
        public static string EnumValue(this MyEnum e) {
            switch (e) {
                case MyEnum.First:
                    return "First Friendly Value";
                case MyEnum.Second:
                    return "Second Friendly Value";
                case MyEnum.Third:
                    return "Third Friendly Value";
            }
            return "Horrible Failure!!";
        }
    }
}

С помощью этого метода расширения теперь допустимо следующее:

Console.WriteLine(MyEnum.First.EnumValue());

Надеюсь, это поможет !!

33
ответ дан 23 November 2019 в 20:49
поделиться

Одна из проблем этого трюка заключается в том, что атрибут описания не может быть локализован. Мне нравится техника Саши Барбера, в которой он создает свою собственную версию атрибута Description, которая будет получать значения из соответствующего диспетчера ресурсов.

http://www.codeproject.com/KB/WPF/FriendlyEnums.aspx

] Хотя статья посвящена проблеме, с которой обычно сталкиваются разработчики WPF при привязке к перечислениям, вы можете сразу перейти к той части, где он создает LocalizableDescriptionAttribute.

10
ответ дан 23 November 2019 в 20:49
поделиться

Имена перечислений живут по тем же правилам, что и обычные имена переменных, то есть без пробелов или точек в середине имен ... Я все еще считаю первое довольно дружелюбным ...

2
ответ дан 23 November 2019 в 20:49
поделиться

Они следуют тем же правилам именования, что и имена переменных. Поэтому они не должны содержать пробелов.

Также то, что вы предлагаете, в любом случае было бы очень плохой практикой.

3
ответ дан 23 November 2019 в 20:49
поделиться

Вы можете использовать атрибут Описание , как предложил Юрий. Следующий метод расширения упрощает получение описания для заданного значения перечисления:

public static string GetDescription(this Enum value)
{
    Type type = value.GetType();
    string name = Enum.GetName(type, value);
    if (name != null)
    {
        FieldInfo field = type.GetField(name);
        if (field != null)
        {
            DescriptionAttribute attr = 
                   Attribute.GetCustomAttribute(field, 
                     typeof(DescriptionAttribute)) as DescriptionAttribute;
            if (attr != null)
            {
                return attr.Description;
            }
        }
    }
    return null;
}

Вы можете использовать его так:

public enum MyEnum
{
    [Description("Description for Foo")]
    Foo,
    [Description("Description for Bar")]
    Bar
}

MyEnum x = MyEnum.Foo;
string description = x.GetDescription();
373
ответ дан 23 November 2019 в 20:49
поделиться

Нет, но вы можете использовать DescriptionAttribute , чтобы выполнить то, что вы ищете.

23
ответ дан 23 November 2019 в 20:49
поделиться

Вы можете использовать атрибут Описание , чтобы получить это понятное имя. Вы можете использовать приведенный ниже код:

public static string ToStringEnums(Enum en)
{
    Type type = en.GetType();

    MemberInfo[] memInfo = type.GetMember(en.ToString());
    if (memInfo != null && memInfo.Length > 0)
    {
        object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
        if (attrs != null && attrs.Length > 0)
            return ((DescriptionAttribute)attrs[0]).Description;
    }
    return en.ToString();
}

Пример того, когда вы хотели бы использовать этот метод: когда ваше значение перечисления EncryptionProviderType и вы хотите, чтобы enumVar.Tostring () возвращал «Тип поставщика шифрования».

Предварительное условие: все члены перечисления должны применяться с атрибутом [Описание («Строка, возвращаемая Tostring ()»)] .

Пример перечисления:

enum ExampleEnum
{
    [Description("One is one")]
    ValueOne = 1,
    [Description("Two is two")]
    ValueTow = 2
}

И в вашем классе, вы бы использовали его так:

ExampleEnum enumVar = ExampleEnum.ValueOne;
Console.WriteLine(ToStringEnums(enumVar));
14
ответ дан 23 November 2019 в 20:49
поделиться
public enum myEnum
{
         ThisNameWorks, 
         This_Name_can_be_used_instead,

}
4
ответ дан 23 November 2019 в 20:49
поделиться

Я полагаю, что вы хотите показать свои значения перечисления пользователю, поэтому вы хотите, чтобы у них было какое-то понятное имя.

Вот мой предложение:

Используйте шаблон типа enum. Хотя для реализации требуются некоторые усилия, это действительно того стоит.

public class MyEnum
{  
    public static readonly MyEnum Enum1=new MyEnum("This will work",1);
    public static readonly MyEnum Enum2=new MyEnum("This.will.work.either",2);
    public static readonly MyEnum[] All=new []{Enum1,Enum2};
    private MyEnum(string name,int value)
    {
        Name=name;
        Value=value;
    }

    public string Name{get;set;}
    public int Value{get;set;}

    public override string ToString()
    {
        return Name;    
    }
}
-2
ответ дан 23 November 2019 в 20:49
поделиться

Некоторые замечательные решения уже были опубликованы. Когда я столкнулся с этой проблемой, я хотел пойти обоими путями: преобразовать перечисление в описание и преобразовать строку, соответствующую описанию, в перечисление.

У меня есть два варианта, медленный и быстрый. Оба конвертируют из перечисления в строку и из строки в перечисление. Моя проблема в том, что у меня есть перечисления, подобные этому, где некоторым элементам нужны атрибуты, а некоторым нет. Я не хочу накладывать атрибуты на элементы, которым они не нужны. Всего у меня их около сотни:

public enum POS
{   
    CC, //  Coordinating conjunction
    CD, //  Cardinal Number
    DT, //  Determiner
    EX, //  Existential there
    FW, //  Foreign Word
    IN, //  Preposision or subordinating conjunction
    JJ, //  Adjective
    [System.ComponentModel.Description("WP$")]
    WPDollar, //$   Possessive wh-pronoun
    WRB, //     Wh-adverb
    [System.ComponentModel.Description("#")]
    Hash,
    [System.ComponentModel.Description("$")]
    Dollar,
    [System.ComponentModel.Description("''")]
    DoubleTick,
    [System.ComponentModel.Description("(")]
    LeftParenth,
    [System.ComponentModel.Description(")")]
    RightParenth,
    [System.ComponentModel.Description(",")]
    Comma,
    [System.ComponentModel.Description(".")]
    Period,
    [System.ComponentModel.Description(":")]
    Colon,
    [System.ComponentModel.Description("``")]
    DoubleBackTick,
    };

Первый метод решения этой проблемы медленный и основан на предложениях, которые я видел здесь и в сети. Он медленный, потому что мы отражаем каждое преобразование:

using System;
using System.Collections.Generic;
namespace CustomExtensions
{

/// <summary>
/// uses extension methods to convert enums with hypens in their names to underscore and other variants
public static class EnumExtensions
{
    /// <summary>
    /// Gets the description string, if available. Otherwise returns the name of the enum field
    /// LthWrapper.POS.Dollar.GetString() yields "$", an impossible control character for enums
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string GetStringSlow(this Enum value)
    {
        Type type = value.GetType();
        string name = Enum.GetName(type, value);
        if (name != null)
        {
            System.Reflection.FieldInfo field = type.GetField(name);
            if (field != null)
            {
                System.ComponentModel.DescriptionAttribute attr =
                       Attribute.GetCustomAttribute(field,
                         typeof(System.ComponentModel.DescriptionAttribute)) as System.ComponentModel.DescriptionAttribute;
                if (attr != null)
                {
                    //return the description if we have it
                    name = attr.Description; 
                }
            }
        }
        return name;
    }

    /// <summary>
    /// Converts a string to an enum field using the string first; if that fails, tries to find a description
    /// attribute that matches. 
    /// "$".ToEnum<LthWrapper.POS>() yields POS.Dollar
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value"></param>
    /// <returns></returns>
    public static T ToEnumSlow<T>(this string value) //, T defaultValue)
    {
        T theEnum = default(T);

        Type enumType = typeof(T);

        //check and see if the value is a non attribute value
        try
        {
            theEnum = (T)Enum.Parse(enumType, value);
        }
        catch (System.ArgumentException e)
        {
            bool found = false;
            foreach (T enumValue in Enum.GetValues(enumType))
            {
                System.Reflection.FieldInfo field = enumType.GetField(enumValue.ToString());

                System.ComponentModel.DescriptionAttribute attr =
                           Attribute.GetCustomAttribute(field,
                             typeof(System.ComponentModel.DescriptionAttribute)) as System.ComponentModel.DescriptionAttribute;

                if (attr != null && attr.Description.Equals(value))
                {
                    theEnum = enumValue;
                    found = true;
                    break;

                }
            }
            if( !found )
                throw new ArgumentException("Cannot convert " + value + " to " + enumType.ToString());
        }

        return theEnum;
    }
}
}

Проблема с этим в том, что вы делаете отражение каждый раз. Я не измерял падение производительности от этого, но оно кажется тревожным. Хуже того, мы вычисляем эти дорогостоящие преобразования многократно, не кэшируя их.

Вместо этого мы можем использовать статический конструктор для заполнения некоторых словарей информацией о преобразованиях, а затем просто искать эту информацию, когда это необходимо. Очевидно, статические классы (необходимые для методов расширения) могут иметь конструкторы и поля :)

using System;
using System.Collections.Generic;
namespace CustomExtensions
{

/// <summary>
/// uses extension methods to convert enums with hypens in their names to underscore and other variants
/// I'm not sure this is a good idea. While it makes that section of the code much much nicer to maintain, it 
/// also incurs a performance hit via reflection. To circumvent this, I've added a dictionary so all the lookup can be done once at 
/// load time. It requires that all enums involved in this extension are in this assembly.
/// </summary>
public static class EnumExtensions
{
    //To avoid collisions, every Enum type has its own hash table
    private static readonly Dictionary<Type, Dictionary<object,string>> enumToStringDictionary = new Dictionary<Type,Dictionary<object,string>>();
    private static readonly Dictionary<Type, Dictionary<string, object>> stringToEnumDictionary = new Dictionary<Type, Dictionary<string, object>>();

    static EnumExtensions()
    {
        //let's collect the enums we care about
        List<Type> enumTypeList = new List<Type>();

        //probe this assembly for all enums
        System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
        Type[] exportedTypes = assembly.GetExportedTypes();

        foreach (Type type in exportedTypes)
        {
            if (type.IsEnum)
                enumTypeList.Add(type);
        }

        //for each enum in our list, populate the appropriate dictionaries
        foreach (Type type in enumTypeList)
        {
            //add dictionaries for this type
            EnumExtensions.enumToStringDictionary.Add(type, new Dictionary<object,string>() );
            EnumExtensions.stringToEnumDictionary.Add(type, new Dictionary<string,object>() );

            Array values = Enum.GetValues(type);

            //its ok to manipulate 'value' as object, since when we convert we're given the type to cast to
            foreach (object value in values)
            {
                System.Reflection.FieldInfo fieldInfo = type.GetField(value.ToString());

                //check for an attribute 
                System.ComponentModel.DescriptionAttribute attribute =
                       Attribute.GetCustomAttribute(fieldInfo,
                         typeof(System.ComponentModel.DescriptionAttribute)) as System.ComponentModel.DescriptionAttribute;

                //populate our dictionaries
                if (attribute != null)
                {
                    EnumExtensions.enumToStringDictionary[type].Add(value, attribute.Description);
                    EnumExtensions.stringToEnumDictionary[type].Add(attribute.Description, value);
                }
                else
                {
                    EnumExtensions.enumToStringDictionary[type].Add(value, value.ToString());
                    EnumExtensions.stringToEnumDictionary[type].Add(value.ToString(), value);
                }
            }
        }
    }

    public static string GetString(this Enum value)
    {
        Type type = value.GetType();
        string aString = EnumExtensions.enumToStringDictionary[type][value];
        return aString; 
    }

    public static T ToEnum<T>(this string value)
    {
        Type type = typeof(T);
        T theEnum = (T)EnumExtensions.stringToEnumDictionary[type][value];
        return theEnum;
    }
 }
}

Посмотрите, насколько плотно теперь работают методы преобразования. Единственный недостаток, о котором я могу думать, это то, что это требует, чтобы все преобразованные перечисления находились в текущей сборке. Кроме того, я беспокоюсь только об экспортируемых перечислениях, но вы можете изменить это, если захотите.

Вот как вызывать методы

 string x = LthWrapper.POS.Dollar.GetString();
 LthWrapper.POS y = "PRP$".ToEnum<LthWrapper.POS>();
8
ответ дан 23 November 2019 в 20:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: