How to get all descriptions of enum values with re

2019-03-30 06:43发布

So I need to get a List<string> from my enum

Here is what I have done so far:

enum definition

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

HelperClass with method to do what I need:

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

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

Now in the line where I yield values, I got a NullReferenceException. Did I miss something? The syntax looks all right to me, but maybe I overlooked something?

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

7条回答
在下西门庆
2楼-- · 2019-03-30 07:08

It think this can solve your problem. If it is not implemented you can return null or an exception. It depends what you need.

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");
}

So you will use it like this :

DescriptionAttribute attribute = GetDescription(ContractorType.RECIPIENT);

Sorry that I didn't read your question. Here is some code that you can use to take all of the description strings:

 public IEnumerable<string> GetAllDescriptionInText()
 {
     List<string> descList = new List<string>();
     foreach (DescriptionAttribute desc in Enum.GetValues(typeof(DescriptionAttribute)))
     {
         descList.Add(GetDescription(desc).Value);
     }
     return descList;
 }
查看更多
干净又极端
3楼-- · 2019-03-30 07:13

You need to find the DescriptionAttribute on each field, if it exists and then retrieve the Description attribute e.g.

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

If you could have multiple descriptions on a field, you could do something like:

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

which is more similar to your existing approach.

查看更多
SAY GOODBYE
4楼-- · 2019-03-30 07:14

I created these extension methods

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<T, string> GetEnumValuesWithDescription<T>(this Type type) where T : struct, IConvertible
    {
        if (!type.IsEnum)
        {
            throw new ArgumentException("T must be an enumerated type");
        }

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

Usage

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

Will return a Dictionary<TestEnum, string> 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()
查看更多
萌系小妹纸
5楼-- · 2019-03-30 07:15

Here is a small reusable solution. This is an abstract class which will extract all the attributes of type K from type T.

abstract class AbstractAttributes<T, K>
{
    protected List<K> Attributes = new List<K>();

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

Should we now want to extract only attributes of DescriptionAttribute type, we would use the following class.

class DescriptionAttributes<T> : AbstractAttributes<T, DescriptionAttribute>
{
    public List<string> Descriptions { get; set; }

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

This class will extract only attributes of DescriptionAttribute type from the type T. But to actually use this class in you context you will simply need to do the following.

new DescriptionAttributes<ContractorType>().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<T, K> class and close its type K with the appropriate attribute.

查看更多
Ridiculous、
6楼-- · 2019-03-30 07:17

You can try this

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();
    }
}
查看更多
来,给爷笑一个
7楼-- · 2019-03-30 07:18

This generic static method works fine for getting a list of descriptions for each value of an enum type of T:

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

    return attributes.Select(x => x.Description);
}
查看更多
登录 后发表回答