How to get all descriptions of enum values with reflection? - c#

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.

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

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()

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.

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.

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

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

This is Dictionary not List
But is is something I use
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<enumDateCond, string> DLenumDateCond = EnumToDictionary<enumDateCond>();
foreach(enumDateCond key in DLenumDateCond.Keys)
{
Console.WriteLine(key.ToString() + " " + DLenumDateCond[key]);
}
}
public static Dictionary<T, string> EnumToDictionary<T>()
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<T, string> enumDL = new Dictionary<T, string>();
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;
}
}
}

Related

How to get a custom attribute on enum by passing in the enum value and attribute type?

there are lots of examples online of creating a enum extension method that takes a enum value as an argument and in the method gets a specific attribute, like so:
namespace MVVMProj.ProjUtilities
{
public class EnumerationHelpers
{
public static string GetStatusText(this Enum value)
{
var type = value.GetType();
string name = Enum.GetName(type, value);
if (name == null) { return null; }
var field = type.GetField(name);
if (field == null) { return null; }
var attr = Attribute.GetCustomAttribute(field, typeof(StatusTextAttribute)) as StatusTextAttribute;
if (attr == null) { return null; }
return attr.StatusText;
}
}
}
What I'm wondering is, is there a way to also pass the method the attribute type, so I don't need to keep writing specific methods for each different attribute?
This is unfinished, but, it should give you the idea of what I'm trying to achieve:
namespace MVVMProj.ProjUtilities
{
public class EnumerationHelpers
{
public static string GetCustomAttribute(this Enum value, Type customAttr)
//Or instead of passing a Type, a string of the attribute's name
{
var type = value.GetType();
string name = Enum.GetName(type, value);
if (name == null) { return null; }
var field = type.GetField(name);
if (field == null) { return null; }
var attr = Attribute.GetCustomAttribute(field, ....) as ....;
if (attr == null) { return null; }
return attr....;
}
}
}
I suppose I can't just return a string either as it could be any data type.
Some generic method maybe?
Any advice would be greatly appreciated!
Edit: Usage:
It is iterating over the enum creating a dictionary so I can display the values in a combobox. It only adds the item if the attribute matches the condition in the if statement.
One more thing to note is that the custom attribute is an enum as well.
Aybe: the 'item' is only an object upon the iteration so I do a cast. Though I am getting an error in the if statement, it trying to compare CaseTypeAttribute to an actual CaseType enum value, what do I need to do to resolve?
Error:
Severity Code Description Project File Line Suppression State
Error CS0019 Operator '==' cannot be applied to operands of type 'SBC.CaseTypeAttribute' and 'SBC.CaseType'
private Dictionary<int, string> _substancetypes;
public Dictionary<int, string> SubstanceTypes
{
get
{
if (_substancetypes == null)
{
_substancetypes = new Dictionary<int, string>();
foreach (var item in Enum.GetValues(typeof(SBC.SubstanceTypeCode)))
{
var descriptionAttribute = ((SBC.SubstanceTypeCode)item).GetAttribute<SBC.CaseTypeAttribute>();
if (descriptionAttribute != null &&
descriptionAttribute == SBC.CaseType.Exposures) //Error here
{
_substancetypes.Add((int)item, CTS_MVVM.CTS_Utilities.EnumerationHelpers.GetDescriptionFromEnumValue((SBC.SubstanceTypeCode)item));
}
}
}
return _substancetypes;
}
}
Something like this?
using System;
using System.ComponentModel;
using System.Reflection;
namespace ConsoleApp1
{
internal static class Program
{
private static void Main(string[] args)
{
var descriptionAttribute = MyEnum.A.GetAttribute<DescriptionAttribute>();
}
}
public static class EnumExtensions
{
public static T GetAttribute<T>(this Enum #enum) where T : Attribute
{
var type = #enum.GetType();
var name = Enum.GetName(type, #enum);
var field = type.GetField(name);
var attribute = field.GetCustomAttribute<T>();
return attribute;
}
}
public enum MyEnum
{
[Description("A")] A,
[Description("B")] B
}
}

Enum to list as an extension?

I have various enums that I use as sources for dropdown lists, In order to provide for a user-friendly description, I added a Description attribute to each enum, and then do the following:
var list = Enum.GetValues(typeof(MyEnum))
.Cast<MyEnum>()
.ToDictionary(k => k, v => v.GetAttributeOfType<DescriptionAttribute>().Description)
.ToList();
The above is repetitive because I have to use it in a lot of places. I tried to add an extension method:
public static T GetAttributeOfType<T>(this Enum enumVal) where T : System.Attribute
{
var type = enumVal.GetType();
var memInfo = type.GetMember(enumVal.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
return (attributes.Length > 0) ? (T)attributes[0] : null;
}
public static KeyValuePair<T, string> ToList<T>(this Enum source)
{
return Enum.GetValues(typeof(T))
.Cast<T>()
.ToDictionary(k => k, v => v.GetAttributeOfType<DescriptionAttribute>().Description)
.ToList();
}
However, I get an exception:
Cannot convert lambda expression to type 'System.Collections.Generic.IEqualityComparer' because it is not a delegate type
What is the correct way to use it as an extension (using the above 2 methods)?
What is the correct way to use it as an extension (using the above 2 methods)?
There is no correct way to use it as an extension. Extension methods (similar to instance methods) are used when you have a value (instance) and for instance want to get some information related to that value. So the extension method would make sense if you want to get the description of a single enum value.
However, in your case the information you need (the list of enum value/description pairs) is not tied to a specific enum value, but to the enum type. Which means you just need a plain static generic method similar to Enum.TryParse<TEnum>. Ideally you would constrain the generic argument to allow only enum, but this type of constraint is not supported (yet), so we'll use (similar to the above system method) just where TEnum : struct and will add runtime check.
So here is a sample implementation:
public static class EnumInfo
{
public static List<KeyValuePair<TEnum, string>> GetList<TEnum>()
where TEnum : struct
{
if (!typeof(TEnum).IsEnum) throw new InvalidOperationException();
return ((TEnum[])Enum.GetValues(typeof(TEnum)))
.ToDictionary(k => k, v => ((Enum)(object)v).GetAttributeOfType<DescriptionAttribute>().Description)
.ToList();
}
}
and usage:
public enum MyEnum
{
[Description("Foo")]
A,
[Description("Bar")]
B,
[Description("Baz")]
C,
}
var list = EnumInfo.GetList<MyEnum>();
I have this extension method in my stack and use it for the same thing all the time.
public static string Description(this Enum #enum)
{
try
{
var #string = #enum.ToString();
var attribute =
#enum.GetType()
.GetField(#string)
.GetCustomAttribute<DescriptionAttribute>(false);
return attribute != null ? attribute.Description : #string;
}
catch // Log nothing, just return an empty string
{
return string.Empty;
}
}
Example usage:
MyEnum.Value.Description(); // The value from within the description attr.
Additionally, you can use this one to get a IDictionary for binding purposes.
public static IDictionary<string, string> ToDictionary(this Type type)
{
if (!type.IsEnum)
{
throw new InvalidCastException("'enumValue' is not an Enumeration!");
}
var names = Enum.GetNames(type);
var values = Enum.GetValues(type);
return Enumerable.Range(0, names.Length)
.Select(index => new
{
Key = names[index],
Value = ((Enum)values.GetValue(index)).Description()
})
.ToDictionary(k => k.Key, k => k.Value);
}
Use it like so:
var dictionary = typeof(MyEnum).ToDictionary();
Update
Here is a working .NET Fiddle.
public static Dictionary<TEnum, string> ToDictionary<TEnum>(this Type type)
where TEnum : struct, IComparable, IFormattable, IConvertible
{
return Enum.GetValues(type)
.OfType<TEnum>()
.ToDictionary(value => value, value => value.Description());
}
Then use it like this:
public enum Test
{
[Description("A test enum value for 'Foo'")]
Foo,
[Description("A test enum value for 'Bar'")]
Bar
}
typeof(Test).ToDictionary<Test>()
You can create a generic method which would take Enum and Attribute as generic argument.
For getting any attribute, you can create an extension method like:
public static string AttributeValue<TEnum,TAttribute>(this TEnum value,Func<TAttribute,string> func) where T : Attribute
{
FieldInfo field = value.GetType().GetField(value.ToString());
T attribute = Attribute.GetCustomAttribute(field, typeof(T)) as T;
return attribute == null ? value.ToString() : func(attribute);
}
and here is the method for converting it to dictionary:
public static Dictionary<TEnum,string> ToDictionary<TEnum,TAttribute>(this TEnum obj,Func<TAttribute,string> func)
where TEnum : struct, IComparable, IFormattable, IConvertible
where TAttribute : Attribute
{
return (Enum.GetValues(typeof(TEnum)).OfType<TEnum>()
.Select(x =>
new
{
Value = x,
Description = x.AttributeValue<TEnum,TAttribute>(func)
}).ToDictionary(x=>x.Value,x=>x.Description));
}
You can call it this way:
var test = eUserRole.SuperAdmin
.ToDictionary<eUserRole,EnumDisplayNameAttribute>(attr=>attr.DisplayName);
I have used this Enum and Attribute as example:
public class EnumDisplayNameAttribute : Attribute
{
private string _displayName;
public string DisplayName
{
get { return _displayName; }
set { _displayName = value; }
}
}
public enum eUserRole : int
{
[EnumDisplayName(DisplayName = "Super Admin")]
SuperAdmin = 0,
[EnumDisplayName(DisplayName = "Phoenix Admin")]
PhoenixAdmin = 1,
[EnumDisplayName(DisplayName = "Office Admin")]
OfficeAdmin = 2,
[EnumDisplayName(DisplayName = "Report User")]
ReportUser = 3,
[EnumDisplayName(DisplayName = "Billing User")]
BillingUser = 4
}
Output:
Another take on this:
class Program
{
//Example enum
public enum eFancyEnum
{
[Description("Obsolete")]
Yahoo,
[Description("I want food")]
Meow,
[Description("I want attention")]
Woof,
}
static void Main(string[] args)
{
//This is how you use it
Dictionary<eFancyEnum, string> myDictionary = typeof(eFancyEnum).ToDictionary<eFancyEnum>();
}
}
public static class EnumExtension
{
//Helper method to get description
public static string ToDescription<T>(this T 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();
}
//The actual extension method that builds your dictionary
public static Dictionary<T, string> ToDictionary<T>(this Type source) where T : struct, IConvertible
{
if(!source.IsEnum || typeof(T) != source)
{
throw new InvalidEnumArgumentException("BOOM");
}
Dictionary<T, string> retVal = new Dictionary<T,string>();
foreach (var item in Enum.GetValues(typeof(T)).Cast<T>())
{
retVal.Add(item, item.ToDescription());
}
return retVal;
}
}
Whenever I need an enumeration (a static list of known values) that need to have something more than just a mere integer value and a string counterpart, I end up using this Enumeration Utility class that essentially gives me java-like enumeration behavior.
So that would be my first option if I were on op's shoes as it would make it really trivial to achieve what he/she wants.
But, assuming this is not an option for op and she/he need to stick with C# enums, I would use a combination of both ehsan-sajjad and frank-j solutions:
Have an extension method to return the description of a given enum
item, which is pretty much what op had already;
Have a static helper method to return a dictionary of items and their respective descriptions for a given enum type.
Here is how I would implement this:
public static class EnumUtils
{
public static string GetDescription(this Enum enumVal)
{
var type = enumVal.GetType();
var memInfo = type.GetMember(enumVal.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof (DescriptionAttribute), false);
return (attributes.Length > 0) ? ((DescriptionAttribute) attributes[0]).Description : null;
}
public static Dictionary<TEnum, string> GetItemsWithDescrition<TEnum>()
{
var enumType = typeof(TEnum);
if (!enumType.IsEnum)
{
throw new InvalidOperationException("TEnum must be an enum type");
}
return Enum
.GetValues(enumType)
.Cast<TEnum>()
.ToDictionary(enumValue => enumValue, enumValue => GetDescription(enumValue as Enum));
}
}
And here is what the usage would look like:
public class EnumUtilsTests
{
public enum MyEnum
{
[Description("Um")]
One,
[Description("Dois")]
Two,
[Description("Tres")]
Three,
NoDescription
}
public void Should_get_enum_description()
{
MyEnum.One.GetDescription().ShouldBe("Um");
MyEnum.Two.GetDescription().ShouldBe("Dois");
MyEnum.Three.GetDescription().ShouldBe("Tres");
MyEnum.NoDescription.GetDescription().ShouldBe(null);
}
public void Should_get_all_enum_values_with_description()
{
var response = EnumUtils.GetItemsWithDescrition<MyEnum>();
response.ShouldContain(x => x.Key == MyEnum.One && x.Value == "Um");
response.ShouldContain(x => x.Key == MyEnum.Two && x.Value == "Dois");
response.ShouldContain(x => x.Key == MyEnum.Three && x.Value == "Tres");
response.ShouldContain(x => x.Key == MyEnum.NoDescription && x.Value == null);
}
}
Try replacing
.ToDictionary(k => k, v => v.GetAttributeOfType<DescriptionAttribute>().Description)
with
.Select(t => new { k = t, v = t.GetAttributeOfType<DescriptionAttribute>().Description)
.ToDictionary(s => s.k, s => s.v)
In your example, the wrong overload of ToDictionary() is being called.

Generics, enums and custom attributes - is it possible?

Apologies for the amount of code, but it is easier to explain it this way.
I have a custom attribute CustomUserData implemented as follows:
public class CustomUserData : Attribute
{
public CustomUserData(object aUserData)
{
UserData = aUserData;
}
public object UserData { get; set; }
}
and an extension method for enums as:
public static class EnumExtensions
{
public static TAttribute GetAttribute<TAttribute>(this Enum aValue) where TAttribute : Attribute
{
Type type = aValue.GetType();
string name = Enum.GetName(type, aValue);
return type.GetField(name)
.GetCustomAttributes(false)
.OfType<TAttribute>()
.SingleOrDefault();
}
public static object GetCustomUserData(this Enum aValue)
{
CustomUserData userValue = GetAttribute<CustomUserData>(aValue);
return userValue != null ? userValue.UserData : null;
}
}
I then have a helper class that serializes/deserializes an enum that has custom data associated with it as follows:
public static class ParameterDisplayModeEnumListHelper
{
public static List<ParameterDisplayModeEnum> FromDatabase(string aDisplayModeString)
{
//Default behaviour
List<ParameterDisplayModeEnum> result = new List<ParameterDisplayModeEnum>();
//Split the string list into a list of strings
List<string> listOfDisplayModes = new List<string>(aDisplayModeString.Split(','));
//Iterate the enum looking for matches in the list
foreach (ParameterDisplayModeEnum displayModeEnum in Enum.GetValues(typeof (ParameterDisplayModeEnum)))
{
if (listOfDisplayModes.FindIndex(item => item == (string)displayModeEnum.GetCustomUserData()) >= 0)
{
result.Add(displayModeEnum);
}
}
return result;
}
public static string ToDatabase(List<ParameterDisplayModeEnum> aDisplayModeList)
{
string result = string.Empty;
foreach (ParameterDisplayModeEnum listItem in aDisplayModeList)
{
if (result != string.Empty)
result += ",";
result += listItem.GetCustomUserData();
}
return result;
}
}
however this is specific to ParameterDisplayModeEnum and I have a bunch of enums that I need to treat this way for serialization/deserialization so I would prefer to have a generic such as:
public static class EnumListHelper<TEnum>
{
public static List<TEnum> FromDatabase(string aDisplayModeString)
{
//Default behaviour
List<TEnum> result = new List<TEnum>();
//Split the string list into a list of strings
List<string> listOfDisplayModes = new List<string>(aDisplayModeString.Split(','));
//Iterate the enum looking for matches in the list
foreach (TEnum displayModeEnum in Enum.GetValues(typeof (TEnum)))
{
if (listOfDisplayModes.FindIndex(item => item == (string)displayModeEnum.GetCustomUserData()) >= 0)
{
result.Add(displayModeEnum);
}
}
return result;
}
public static string ToDatabase(List<TEnum> aDisplayModeList)
{
string result = string.Empty;
foreach (TEnum listItem in aDisplayModeList)
{
if (result != string.Empty)
result += ",";
result += listItem.GetCustomUserData();
}
return result;
}
}
However this will not work as GetCustomUserData() cannot be invoked. Any suggestions? I cannot change the use of the custom attribute or the use of the enums. I am looking for a generic way to do the serialization/deserialization without having to write a concrete list helper class each time.
All suggestions appreciated.
Try this code:
public static class EnumListHelper
{
private static void EnsureIsEnum<TEnum>()
{
if (!typeof(TEnum).IsEnum)
throw new InvalidOperationException(string.Format("The {0} type is not an enum.", typeof(TEnum)));
}
public static List<TEnum> FromDatabase<TEnum>(string aDisplayModeString)
where TEnum : struct
{
EnsureIsEnum<TEnum>();
//Default behaviour
List<TEnum> result = new List<TEnum>();
//Split the string list into a list of strings
List<string> listOfDisplayModes = new List<string>(aDisplayModeString.Split(','));
//Iterate the enum looking for matches in the list
foreach (Enum displayModeEnum in Enum.GetValues(typeof(TEnum)))
{
if (listOfDisplayModes.FindIndex(item => item == (string)displayModeEnum.GetCustomUserData()) >= 0)
{
result.Add((TEnum)(object)displayModeEnum);
}
}
return result;
}
public static string ToDatabase<TEnum>(List<TEnum> aDisplayModeList)
where TEnum : struct
{
EnsureIsEnum<TEnum>();
string result = string.Empty;
foreach (var listItem in aDisplayModeList.OfType<Enum>())
{
if (result != string.Empty)
result += ",";
result += listItem.GetCustomUserData();
}
return result;
}
}
var fromDatabase = EnumListHelper.FromDatabase<TestEnum>("test");
EnumListHelper.ToDatabase(fromDatabase);
UPDATE 0
To be clear, because we cannot restrict generics to Enum we should check that the type TEnum is an enum and throw an exception if it is not.
When we use the FromDatabase method we know that TEnum is enum, and we can write this code to cast an enum to the specified TEnum:
result.Add((TEnum)(object)displayModeEnum)
in the ToDatabase method we also know that TEnum is enum and we can write this code to convert TEnum to the Enum type:
aDisplayModeList.OfType<Enum>()
Ideally you'd want to restrict TEnum to Enum but that won't work as you can not restrict generics to Enum MicrosoftBut try following, it might do the trick...
if (listOfDisplayModes.FindIndex(item =>
item == (string)(displayModeEnum as Enum).GetCustomUserData()) >= 0)

Access to the value of a Custom Attribute

I've got this custom attribute:
[AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited = true)]
class MethodTestingAttibute : Attribute
{
public string Value{ get; private set; }
public MethodTestingAttibute (string value)
{
this.Value= value;
}
}
To be used like this:
[MethodTestingAttibute("2")]
public int m1() {return 3; }
And my difficulty is to take the value of "2" of MethodTestingAttibute
object result = method.Invoke(obj, new Type[] {}); // here i get the return
Now I want to compare this result to the value of MethodTestingAttibute. How can I do that? I'm trying to go up to this road but without success:
method.GetCustomAttributes(typeof(MethodTestAttibute), true)[0]...
What is the proper way to get access to the field of the custom attribute?
var attribute =
(MethodTestingAttibute)
typeof (Vehicles)
.GetMethod("m1")
.GetCustomAttributes(typeof (MethodTestingAttibute), false).First();
Console.WriteLine(attribute.Value);
With my custom attribute:
[AttributeUsage(AttributeTargets.Method)]
public class AttributeCustom : Attribute
{
public string MyPropertyAttribute { get; private set; }
public AttributeCustom(string myproperty)
{
this.MyPropertyAttribute = myproperty;
}
}
I create a method for to get attribute with his values:
public static AttributeCustom GetAttributeCustom<T>(string method) where T : class
{
try
{
return ((AttributeCustom)typeof(T).GetMethod(method).GetCustomAttributes(typeof(AttributeCustom), false).FirstOrDefault());
}
catch(SystemException)
{
return null;
}
}
With a example class (must be not static because T is generic)
public class MyClass
{
[AttributeCustom("value test attribute")])
public void MyMethod()
{
//...
}
}
Usage:
var customAttribute = GetAttributeCustom<MyClass>("MyMethod");
if (customAttribute != null)
{
Console.WriteLine(customAttribute.MyPropertyAttribute);
}
Cast the object to MethodTestingAttibute:
object actual = method.Invoke(obj, null);
MethodTestingAttibute attribute = (MethodTestingAttibute)method.GetCustomAttributes(typeof(MethodTestAttribute), true)[0];
string expected = attribute.Value;
bool areEqual = string.Equals(expected, actual != null ? actual.ToString() : null, StringComparison.Ordinal);
To get the value of an attribute property, just cast the object returned by GetCustomAttributes():
{
string val;
object[] atts = method.GetCustomAttributes(typeof(MethodTestAttibute), true);
if (atts.Length > 0)
val = (atts[0] as MethodTestingAttibute).Value;
}
Necromancing.
For those that still have to maintain .NET 2.0, or those that want to do it without LINQ:
public static object GetAttribute(System.Reflection.MemberInfo mi, System.Type t)
{
object[] objs = mi.GetCustomAttributes(t, true);
if (objs == null || objs.Length < 1)
return null;
return objs[0];
}
public static T GetAttribute<T>(System.Reflection.MemberInfo mi)
{
return (T)GetAttribute(mi, typeof(T));
}
public delegate TResult GetValue_t<in T, out TResult>(T arg1);
public static TValue GetAttributValue<TAttribute, TValue>(System.Reflection.MemberInfo mi, GetValue_t<TAttribute, TValue> value) where TAttribute : System.Attribute
{
TAttribute[] objAtts = (TAttribute[])mi.GetCustomAttributes(typeof(TAttribute), true);
TAttribute att = (objAtts == null || objAtts.Length < 1) ? default(TAttribute) : objAtts[0];
// TAttribute att = (TAttribute)GetAttribute(mi, typeof(TAttribute));
if (att != null)
{
return value(att);
}
return default(TValue);
}
Example usage:
System.Reflection.FieldInfo fi = t.GetField("PrintBackground");
wkHtmlOptionNameAttribute att = GetAttribute<wkHtmlOptionNameAttribute>(fi);
string name = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, delegate(wkHtmlOptionNameAttribute a){ return a.Name;});
or in your case simply
MethodInfo mi = typeof(Vehicles).GetMethod("m1");
string aValue = GetAttributValue<MethodTestingAttibute, string>(mi, a => a.Value);
Check the code here http://msdn.microsoft.com/en-us/library/bfwhbey7.aspx
Excerpt:
// Get the AClass type to access its metadata.
Type clsType = typeof(AClass);
// Get the type information for Win32CallMethod.
MethodInfo mInfo = clsType.GetMethod("Win32CallMethod");
if (mInfo != null)
{
// Iterate through all the attributes of the method.
foreach(Attribute attr in
Attribute.GetCustomAttributes(mInfo)) {
// Check for the Obsolete attribute.
if (attr.GetType() == typeof(ObsoleteAttribute))
{
Console.WriteLine("Method {0} is obsolete. " +
"The message is:",
mInfo.Name);
Console.WriteLine(" \"{0}\"",
((ObsoleteAttribute)attr).Message);
}
// Check for the Unmanaged attribute.
else if (attr.GetType() == typeof(UnmanagedAttribute))
{
Console.WriteLine(
"This method calls unmanaged code.");
Console.WriteLine(
String.Format("The Unmanaged attribute type is {0}.",
((UnmanagedAttribute)attr).Win32Type));
AClass myCls = new AClass();
myCls.Win32CallMethod();
}
}
}

Reflection - get attribute name and value on property

I have a class, lets call it Book with a property called Name. With that property, I have an attribute associated with it.
public class Book
{
[Author("AuthorName")]
public string Name
{
get; private set;
}
}
In my main method, I'm using reflection and wish to get key value pair of each attribute for each property. So in this example, I'd expect to see "Author" for attribute name and "AuthorName" for the attribute value.
Question: How do I get the attribute name and value on my properties using Reflection?
Use typeof(Book).GetProperties() to get an array of PropertyInfo instances. Then use GetCustomAttributes() on each PropertyInfo to see if any of them have the Author Attribute type. If they do, you can get the name of the property from the property info and the attribute values from the attribute.
Something along these lines to scan a type for properties that have a specific attribute type and to return data in a dictionary (note that this can be made more dynamic by passing types into the routine):
public static Dictionary<string, string> GetAuthors()
{
Dictionary<string, string> _dict = new Dictionary<string, string>();
PropertyInfo[] props = typeof(Book).GetProperties();
foreach (PropertyInfo prop in props)
{
object[] attrs = prop.GetCustomAttributes(true);
foreach (object attr in attrs)
{
AuthorAttribute authAttr = attr as AuthorAttribute;
if (authAttr != null)
{
string propName = prop.Name;
string auth = authAttr.Name;
_dict.Add(propName, auth);
}
}
}
return _dict;
}
To get all attributes of a property in a dictionary use this:
typeof(Book)
.GetProperty("Name")
.GetCustomAttributes(false)
.ToDictionary(a => a.GetType().Name, a => a);
remember to change from false to true if you want to include inheritted attributes as well.
If you just want one specific Attribute value For instance Display Attribute you can use the following code:
var pInfo = typeof(Book).GetProperty("Name")
.GetCustomAttribute<DisplayAttribute>();
var name = pInfo.Name;
I have solved similar problems by writing a Generic Extension Property Attribute Helper:
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
public static class AttributeHelper
{
public static TValue GetPropertyAttributeValue<T, TOut, TAttribute, TValue>(
Expression<Func<T, TOut>> propertyExpression,
Func<TAttribute, TValue> valueSelector)
where TAttribute : Attribute
{
var expression = (MemberExpression) propertyExpression.Body;
var propertyInfo = (PropertyInfo) expression.Member;
var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute), true).FirstOrDefault() as TAttribute;
return attr != null ? valueSelector(attr) : default(TValue);
}
}
Usage:
var author = AttributeHelper.GetPropertyAttributeValue<Book, string, AuthorAttribute, string>(prop => prop.Name, attr => attr.Author);
// author = "AuthorName"
You can use GetCustomAttributesData() and GetCustomAttributes():
var attributeData = typeof(Book).GetProperty("Name").GetCustomAttributesData();
var attributes = typeof(Book).GetProperty("Name").GetCustomAttributes(false);
If you mean "for attributes that take one parameter, list the attribute-names and the parameter-value", then this is easier in .NET 4.5 via the CustomAttributeData API:
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
public static class Program
{
static void Main()
{
PropertyInfo prop = typeof(Foo).GetProperty("Bar");
var vals = GetPropertyAttributes(prop);
// has: DisplayName = "abc", Browsable = false
}
public static Dictionary<string, object> GetPropertyAttributes(PropertyInfo property)
{
Dictionary<string, object> attribs = new Dictionary<string, object>();
// look for attributes that takes one constructor argument
foreach (CustomAttributeData attribData in property.GetCustomAttributesData())
{
if(attribData.ConstructorArguments.Count == 1)
{
string typeName = attribData.Constructor.DeclaringType.Name;
if (typeName.EndsWith("Attribute")) typeName = typeName.Substring(0, typeName.Length - 9);
attribs[typeName] = attribData.ConstructorArguments[0].Value;
}
}
return attribs;
}
}
class Foo
{
[DisplayName("abc")]
[Browsable(false)]
public string Bar { get; set; }
}
private static Dictionary<string, string> GetAuthors()
{
return typeof(Book).GetProperties()
.SelectMany(prop => prop.GetCustomAttributes())
.OfType<AuthorAttribute>()
.ToDictionary(a => a.GetType().Name.Replace("Attribute", ""), a => a.Name);
}
Example using generics (target framework 4.5)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
private static Dictionary<string, string> GetAttribute<TAttribute, TType>(
Func<TAttribute, string> valueFunc)
where TAttribute : Attribute
{
return typeof(TType).GetProperties()
.SelectMany(p => p.GetCustomAttributes())
.OfType<TAttribute>()
.ToDictionary(a => a.GetType().Name.Replace("Attribute", ""), valueFunc);
}
Usage
var dictionary = GetAttribute<AuthorAttribute, Book>(a => a.Name);
public static class PropertyInfoExtensions
{
public static TValue GetAttributValue<TAttribute, TValue>(this PropertyInfo prop, Func<TAttribute, TValue> value) where TAttribute : Attribute
{
var att = prop.GetCustomAttributes(
typeof(TAttribute), true
).FirstOrDefault() as TAttribute;
if (att != null)
{
return value(att);
}
return default(TValue);
}
}
Usage:
//get class properties with attribute [AuthorAttribute]
var props = typeof(Book).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(AuthorAttribute)));
foreach (var prop in props)
{
string value = prop.GetAttributValue((AuthorAttribute a) => a.Name);
}
or:
//get class properties with attribute [AuthorAttribute]
var props = typeof(Book).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(AuthorAttribute)));
IList<string> values = props.Select(prop => prop.GetAttributValue((AuthorAttribute a) => a.Name)).Where(attr => attr != null).ToList();
While the above most upvoted answers definitely work, I'd suggest using a slightly different approach in some cases.
If your class has multiple properties with always the same attribute and you want to get those attributes sorted into a dictionary, here is how:
var dict = typeof(Book).GetProperties().ToDictionary(p => p.Name, p => p.GetCustomAttributes(typeof(AuthorName), false).Select(a => (AuthorName)a).FirstOrDefault());
This still uses cast but ensures that the cast will always work as you will only get the custom attributes of the type "AuthorName".
If you had multiple Attributes above answers would get a cast exception.
Here are some static methods you can use to get the MaxLength, or any other attribute.
using System;
using System.Linq;
using System.Reflection;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;
public static class AttributeHelpers {
public static Int32 GetMaxLength<T>(Expression<Func<T,string>> propertyExpression) {
return GetPropertyAttributeValue<T,string,MaxLengthAttribute,Int32>(propertyExpression,attr => attr.Length);
}
//Optional Extension method
public static Int32 GetMaxLength<T>(this T instance,Expression<Func<T,string>> propertyExpression) {
return GetMaxLength<T>(propertyExpression);
}
//Required generic method to get any property attribute from any class
public static TValue GetPropertyAttributeValue<T, TOut, TAttribute, TValue>(Expression<Func<T,TOut>> propertyExpression,Func<TAttribute,TValue> valueSelector) where TAttribute : Attribute {
var expression = (MemberExpression)propertyExpression.Body;
var propertyInfo = (PropertyInfo)expression.Member;
var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute),true).FirstOrDefault() as TAttribute;
if (attr==null) {
throw new MissingMemberException(typeof(T).Name+"."+propertyInfo.Name,typeof(TAttribute).Name);
}
return valueSelector(attr);
}
}
Using the static method...
var length = AttributeHelpers.GetMaxLength<Player>(x => x.PlayerName);
Or using the optional extension method on an instance...
var player = new Player();
var length = player.GetMaxLength(x => x.PlayerName);
Or using the full static method for any other attribute (StringLength for example)...
var length = AttributeHelpers.GetPropertyAttributeValue<Player,string,StringLengthAttribute,Int32>(prop => prop.PlayerName,attr => attr.MaximumLength);
Inspired by the Mikael Engver's answer.
I wrote this into a dynamic method since I use lots of attributes throughout my application. Method:
public static dynamic GetAttribute(Type objectType, string propertyName, Type attrType)
{
//get the property
var property = objectType.GetProperty(propertyName);
//check for object relation
return property.GetCustomAttributes().FirstOrDefault(x => x.GetType() == attrType);
}
Usage:
var objectRelAttr = GetAttribute(typeof(Person), "Country", typeof(ObjectRelationAttribute));
var displayNameAttr = GetAttribute(typeof(Product), "Category", typeof(DisplayNameAttribute));
Hope this helps anyone
Necromancing.
For those that still have to maintain .NET 2.0, or those that want to do it without LINQ:
public static object GetAttribute(System.Reflection.MemberInfo mi, System.Type t)
{
object[] objs = mi.GetCustomAttributes(t, true);
if (objs == null || objs.Length < 1)
return null;
return objs[0];
}
public static T GetAttribute<T>(System.Reflection.MemberInfo mi)
{
return (T)GetAttribute(mi, typeof(T));
}
public delegate TResult GetValue_t<in T, out TResult>(T arg1);
public static TValue GetAttributValue<TAttribute, TValue>(System.Reflection.MemberInfo mi, GetValue_t<TAttribute, TValue> value) where TAttribute : System.Attribute
{
TAttribute[] objAtts = (TAttribute[])mi.GetCustomAttributes(typeof(TAttribute), true);
TAttribute att = (objAtts == null || objAtts.Length < 1) ? default(TAttribute) : objAtts[0];
// TAttribute att = (TAttribute)GetAttribute(mi, typeof(TAttribute));
if (att != null)
{
return value(att);
}
return default(TValue);
}
Example usage:
System.Reflection.FieldInfo fi = t.GetField("PrintBackground");
wkHtmlOptionNameAttribute att = GetAttribute<wkHtmlOptionNameAttribute>(fi);
string name = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, delegate(wkHtmlOptionNameAttribute a){ return a.Name;});
or simply
string aname = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, a => a.Name );
Just looking for the right place to put this piece of code.
let's say you have the following property:
[Display(Name = "Solar Radiation (Average)", ShortName = "SolarRadiationAvg")]
public int SolarRadiationAvgSensorId { get; set; }
And you want to get the ShortName value. You can do:
((DisplayAttribute)(typeof(SensorsModel).GetProperty(SolarRadiationAvgSensorId).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName;
Or to make it general:
internal static string GetPropertyAttributeShortName(string propertyName)
{
return ((DisplayAttribute)(typeof(SensorsModel).GetProperty(propertyName).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName;
}
foreach (var p in model.GetType().GetProperties())
{
var valueOfDisplay =
p.GetCustomAttributesData()
.Any(a => a.AttributeType.Name == "DisplayNameAttribute") ?
p.GetCustomAttribute<DisplayNameAttribute>().DisplayName :
p.Name;
}
In this example I used DisplayName instead of Author because it has a field named 'DisplayName' to be shown with a value.
to get attribute from enum, i'm using :
public enum ExceptionCodes
{
[ExceptionCode(1000)]
InternalError,
}
public static (int code, string message) Translate(ExceptionCodes code)
{
return code.GetType()
.GetField(Enum.GetName(typeof(ExceptionCodes), code))
.GetCustomAttributes(false).Where((attr) =>
{
return (attr is ExceptionCodeAttribute);
}).Select(customAttr =>
{
var attr = (customAttr as ExceptionCodeAttribute);
return (attr.Code, attr.FriendlyMessage);
}).FirstOrDefault();
}
// Using
var _message = Translate(code);
If you want get property having the custom Attribute then please try the following:
IEnumerable propertyInfos = properties.GetType().GetProperties();
PropertyInfo p = propertyInfos.Where(x => x.GetCustomAttribute() != null);

Categories

Resources