Як атрымаць усе апісання значэнняў пералічэнняў з адлюстраваннем?

So I need to get a List from my enum

Вось тое, што я зрабіў да гэтага часу:

<�Моцны> Вызначэнне пералічэння

    [Flags]
    public enum ContractorType
    {
        [Description("Recipient")]
        RECIPIENT = 1,
        [Description("Deliver")]
        DELIVER = 2,
        [Description("Recipient/Deliver")]
        RECIPIENT_DELIVER = 4
    }

<�Моцны> дапаможны клас з метадам, каб зрабіць тое, што мне трэба:

public static class EnumUtils
{
    public static IEnumerable GetDescrptions(Type enumerator)
    {
        FieldInfo[] fi = enumerator.GetFields();

        List attributes = new List();
        foreach (var i in fi)
        {
            try
            {
                yield return attributes.Add(((DescriptionAttribute[])i.GetCustomAttributes(
                    typeof(DescriptionAttribute),
                    false))[0]);
            }
            catch { }
        }
        return new List{"empty"};
    }
}

Цяпер у радку, дзе я выхад <�код /> значэння, я атрымаў NullReferenceException . Хіба я нешта прапусціў? Сінтаксіс выглядае ўсё правы на мяне, але, магчыма, я нешта прапускае з-пад увагі?

Edit: I'm using .net Framework 4.0 here.

4
Так як гэта (мабыць) а сцягі-пералічэнне, павінна не ваш «Атрымальнік/Deliver» на самай справе будзе значэнне 3? Маўляў, яна не павінна быць камбінацыяй ContractorType.RECIPIENT | ContractorType.DELIVER ? У адваротным выпадку (ContractorType.RECIPIENT | ContractorType.DELIVER)! = ContractorType.RECIPIENT_DELIVER . Можа быць, вы павінны выдаліць [Flags] атрыбут.
дададзена аўтар Chris Sinclair, крыніца

7 адказы

Вось невялікі шматразовы раствор. Гэта абстрактны клас, які будзе здабываць ўсе атрыбуты тыпу K ад тыпу T .

abstract class AbstractAttributes
{
    protected List Attributes = new List();

    public AbstractAttributes()
    {
        foreach (var member in typeof(T).GetMembers())
        {
            foreach (K attribute in member.GetCustomAttributes(typeof(K), true)) 
                Attributes.Add(attribute);                
        }
    }
}

Калі зараз мы хочам, каб дастаць толькі атрыбуты DescriptionAttribute <�код /> тыпу, мы будзем выкарыстоўваць наступны клас.

class DescriptionAttributes : AbstractAttributes
{
    public List Descriptions { get; set; }

    public DescriptionAttributes()
    {
        Descriptions = Attributes.Select(x => x.Description).ToList();
    }
}

Гэты клас будзе здабываць толькі атрыбуты DescriptionAttribute <�код /> тыпу з тыпу T . Але на самой справе выкарыстаць гэты клас у вас кантэксце вам проста трэба зрабіць наступнае.

new DescriptionAttributes().Descriptions.ForEach(x => Console.WriteLine(x));

This line of code will write out all the descriptions you used as parameters in your attributes of type DescriptionAttribute. Should you need to extract some other attributes, just create a new class that derives from the AbstractAttributes class and close its type K with the appropriate attribute.

4
дададзена

Вы павінны знайсці DescriptionAttribute на кожным полі, калі ён існуе, а затым атрымаць Апісанне атрыбут, напрыклад,

return enumType.GetFields()
                .Select(f => (DescriptionAttribute)f.GetCustomAttribute(typeof(DescriptionAttribute)))
                .Where(a => a != null)
                .Select(a => a.Description)

Калі б вы маглі мець некалькі апісанняў на поле, вы маглі б зрабіць нешта накшталт:

FieldInfo[] fields = enumType.GetFields();
foreach(FieldInfo field in fields)
{
    var descriptionAttributes = field.GetCustomAttributes(false).OfType();
    foreach(var descAttr in descriptionAttributes)
    {
        yield return descAttr.Description;
    }
}

які больш падобны на існуючы падыход.

2
дададзена
@ Harry180 - гэта метад пашырэння дададзены ў .NET 4.5, так што вам трэба дадаць , выкарыстоўваючы System.Reflection дырэктывы, калі вы выкарыстоўваеце гэтую версію фреймворка. У якасці альтэрнатывы вы можаце выкарыстоўваць перагрузку з Bool аргументу і перадаць хлусня. Я абнавіў адказ на яго выкарыстоўваць.
дададзена аўтар Lee, крыніца
Там няма GetCustomAttributes() перагрузкі з 0 параметры
дададзена аўтар harry180, крыніца

Я стварыў гэтыя метады пашырэння

public static class EnumExtender
{
    public static string GetDescription(this Enum enumValue)
    {
        string output = null;
        Type type = enumValue.GetType();
        FieldInfo fi = type.GetField(enumValue.ToString());
        var attrs = fi.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];
        if (attrs.Length > 0) output = attrs[0].Description;
        return output;
    }

    public static IDictionary GetEnumValuesWithDescription(this Type type) where T : struct, IConvertible
    {
        if (!type.IsEnum)
        {
            throw new ArgumentException("T must be an enumerated type");
        }

        return type.GetEnumValues()
                .OfType()
                .ToDictionary(
                    key => key,
                    val => (val as Enum).GetDescription()
                );
    }
}

выкарыстанне

var stuff = typeof(TestEnum).GetEnumValuesWithDescription();

Will return a Dictionary with value as keys and descriptions as values. If you want just a list, you can change .ToDictionary to

.Select(o => (o as Enum).GetDescription())
.ToList()
1
дададзена

Гэты агульны статычны метад выдатна падыходзіць для атрымання спісу апісанняў для кожнага значэння тыпу пералічэнняў Т працуе:

public static IEnumerable GetDescriptions()
{
    var attributes = typeof(T).GetMembers()
        .SelectMany(member => member.GetCustomAttributes(typeof (DescriptionAttribute), true).Cast())
        .ToList();

    return attributes.Select(x => x.Description);
}
1
дададзена

Гэта слоўнік не Пералічыце
Але гэта нешта я выкарыстоўваю

using System.ComponentModel;
using System.Reflection;
using MyExtensions;

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

namespace EnumDescription
{
    class Program
    {
        public enum enumDateCond : byte 
        {
            [Description("Empty")]
            Null = 0,
            [Description("Not Empty")]
            NotNull = 1,
            EQ = 2, 
            LT = 3, 
            LE = 4, 
            GE = 14, 
            GT = 15 
        };
        static void Main(string[] args)
        {
            enumDateCond x = enumDateCond.Null;
            string description = x.GetDescriptionName();
            foreach (enumDateCond enm in Enum.GetValues(typeof(enumDateCond)))
            {
                description = enm.GetDescriptionName();
                Console.WriteLine(description);
            }
            Console.WriteLine("Dictionary");
            Dictionary DLenumDateCond = EnumToDictionary();
            foreach(enumDateCond key in DLenumDateCond.Keys)
            {
                Console.WriteLine(key.ToString() + " " + DLenumDateCond[key]);
            }
        }
        public static Dictionary EnumToDictionary()
            where T : struct
        {
            Type enumType = typeof(T);

           //Can't use generic type constraints on value types,
           //so have to do check like this
            if (enumType.BaseType != typeof(Enum))
                throw new ArgumentException("T must be of type System.Enum");

            Dictionary enumDL = new Dictionary();
            foreach (T enm in Enum.GetValues(enumType))
            {
                string name = Enum.GetName(enumType, enm);
                if (name != null)
                {
                    FieldInfo field = enumType.GetField(name);
                    if (field != null)
                    {
                        DescriptionAttribute attr =
                                Attribute.GetCustomAttribute(field,
                                    typeof(DescriptionAttribute)) as DescriptionAttribute;
                        if (attr != null)
                            name = attr.Description;
                    }
                }
                enumDL.Add(enm, name);
            }
            return enumDL;
        }
    }
}
0
дададзена

Гэта думае, што гэта можа вырашыць вашу праблему. Калі гэта не выконваецца вы можаце вярнуць Null або выключэнне. Гэта залежыць ад таго, што вам трэба.

public DescriptionAttribute GetDescription(ContractorType contractorType)
{
     MemberInfo memberInfo = typeof(ContractorType).GetMember(contractorType.ToString())
                                          .FirstOrDefault();

     if (memberInfo != null)
    {
         DescriptionAttribute attribute = (DescriptionAttribute) 
                 memberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false)
                           .FirstOrDefault();
         return attribute;
    }

    //return null;
    //or

    throw new NotImplementedException("There is no description for this enum");
}

Такім чынам, вы будзеце выкарыстоўваць яго як гэта:

DescriptionAttribute attribute = GetDescription(ContractorType.RECIPIENT);

Выбачайце, што я не прачытаў ваша пытанне. Вось код, які вы можаце выкарыстоўваць, каб прыняць усе апісання радкоў:

 public IEnumerable GetAllDescriptionInText()
 {
     List descList = new List();
     foreach (DescriptionAttribute desc in Enum.GetValues(typeof(DescriptionAttribute)))
     {
         descList.Add(GetDescription(desc).Value);
     }
     return descList;
 }
0
дададзена

Вы можаце паспрабаваць гэта

public string ContractorTypeDescription(Enum ContractorType)
{
    FieldInfo fi = ContractorType.GetType().GetField(ContractorType.ToString());
    var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
    if (attributes.Length > 0)
    {
        return attributes[0].Description;
    }
    else
    {
        return ContractorType.ToString();
    }
}
0
дададзена
то вы павінны вызначыць тып пералічэння я думаю, што адзін з вышэйзгаданых адказаў выкарыстоўвае яго
дададзена аўтар COLD TOLD, крыніца
Так, але ваша праца рашэнне толькі для 1 тыпу звычаю пералік , які ва ўзоры ContractorType Я хачу напісаць метад для апрацоўкі ўсіх магчымых карыстацкіх нумаратара ў дадатку. Так што гэта не тое, што я прасіў
дададзена аўтар harry180, крыніца