Localizable dropdown from enum Asp.net MVC - c#

I have dropdown, which is filled from the Enum. My Solution project consists of two parts: Domain and UI projects. And this enum is a part of domain model and so it is placed inside Domain project.
public enum ActivityStatus
{
InProgress = 0,
Completed = 1,
Freezed = 2,
NotStarted = 3,
None = 4
}
I want to localise dropdown content on UI with RESX files. I looked at some solutions, and they proposed providing custom attributes on Enum fields. But I think that localisation is out of scope of my domain model, so i want to have these attributes here. Is there a way to have a localisation on UI for me?

I also have made some enumerations localized in my projects, so, I have a class like this, to create a annotation in enums:
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);
}
}
}
I also have a EnumHelper class to use on my projects to create dictionaries of enums values localized:
public static class EnumHelper
{
// get description data annotation using RESX files when it has
public static string GetDescription(Enum #enum)
{
if (#enum == null)
return null;
string description = #enum.ToString();
try
{
FieldInfo fi = #enum.GetType().GetField(#enum.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Any())
description = attributes[0].Description;
}
catch
{
}
return description;
}
public static IDictionary<TKey, string> GetEnumDictionary<T, TKey>()
where T : struct
{
Type t = typeof (T);
if (!t.IsEnum)
throw new InvalidOperationException("The generic type T must be an Enum type.");
var result = new Dictionary<TKey, string>();
foreach (Enum r in Enum.GetValues(t))
{
var k = Convert.ChangeType(r, typeof(TKey));
var value = (TKey)k;
result.Add(value, r.GetDescription());
}
return result;
}
}
public static class EnumExtensions
{
public static string GetDescription(this Enum #enum)
{
return EnumHelper.GetDescription(#enum);
}
}
With this class you can use on your enum:
public enum ActivityStatus
{
[LocalizedEnum("InProgress", NameResourceType = typeof(Resources.Messages))]
InProgress = 0,
[LocalizedEnum("Completed", NameResourceType = typeof(Resources.Messages))]
Completed = 1,
[LocalizedEnum("Freezed", NameResourceType = typeof(Resources.Messages))]
Freezed = 2,
[LocalizedEnum("NotStarted", NameResourceType = typeof(Resources.Messages))]
NotStarted = 3,
[LocalizedEnum("None", NameResourceType = typeof(Resources.Messages))]
None = 4
}
And to create a combo box of this, you can use on the controller of asp.net mvc, something like this:
var data = EnumHelper.GetEnumDictionary<ActivityStatus, int>();

I guees you can use HttpContext.GetGlobalResourceObject() for getting localized strings for enum names:
// here you get a list of localized strings from `SiteResources.resx` where the keys of strings present by enum names
var names = (Enum.GetNames(typeof(ActivityStatus)).Select(x => HttpContext.GetGlobalResourceObject("SiteResources", x).ToString()).ToList();

Related

Get enum value by name attribute [duplicate]

I would like to know if it is possible to get attributes of the enum values and not of the enum itself? For example, suppose I have the following enum:
using System.ComponentModel; // for DescriptionAttribute
enum FunkyAttributesEnum
{
[Description("Name With Spaces1")]
NameWithoutSpaces1,
[Description("Name With Spaces2")]
NameWithoutSpaces2
}
What I want is given the enum type, produce 2-tuples of enum string value and its description.
Value was easy:
Array values = System.Enum.GetValues(typeof(FunkyAttributesEnum));
foreach (int value in values)
Tuple.Value = Enum.GetName(typeof(FunkyAttributesEnum), value);
But how do I get description attribute's value, to populate Tuple.Desc? I can think of how to do it if the Attribute belongs to the enum itself, but I am at a loss as to how to get it from the value of the enum.
This should do what you need.
try
{
var enumType = typeof(FunkyAttributesEnum);
var memberInfos =
enumType.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString());
var enumValueMemberInfo = memberInfos.FirstOrDefault(m =>
m.DeclaringType == enumType);
var valueAttributes =
enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)valueAttributes[0]).Description;
}
catch
{
return FunkyAttributesEnum.NameWithoutSpaces1.ToString()
}
This piece of code should give you a nice little extension method on any enum that lets you retrieve a generic attribute. I believe it's different to the lambda function above because it's simpler to use and slightly - you only need to pass in the generic type.
public static class EnumHelper
{
/// <summary>
/// Gets an attribute on an enum field value
/// </summary>
/// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
/// <param name="enumVal">The enum value</param>
/// <returns>The attribute of type T that exists on the enum value</returns>
/// <example><![CDATA[string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;]]></example>
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;
}
}
Usage would then be:
string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;
This is a generic implementation using a lambda for the selection
public static Expected GetAttributeValue<T, Expected>(this Enum enumeration, Func<T, Expected> expression)
where T : Attribute
{
T attribute =
enumeration
.GetType()
.GetMember(enumeration.ToString())
.Where(member => member.MemberType == MemberTypes.Field)
.FirstOrDefault()
.GetCustomAttributes(typeof(T), false)
.Cast<T>()
.SingleOrDefault();
if (attribute == null)
return default(Expected);
return expression(attribute);
}
Call it like this:
string description = targetLevel.GetAttributeValue<DescriptionAttribute, string>(x => x.Description);
I've merged a couple of the answers here to create a little more extensible solution. I'm providing it just in case it's helpful to anyone else in the future. Original posting here.
using System;
using System.ComponentModel;
public static class EnumExtensions {
// This extension method is broken out so you can use a similar pattern with
// other MetaData elements in the future. This is your base method for each.
public static T GetAttribute<T>(this Enum value) where T : Attribute {
var type = value.GetType();
var memberInfo = type.GetMember(value.ToString());
var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
return attributes.Length > 0
? (T)attributes[0]
: null;
}
// This method creates a specific call to the above method, requesting the
// Description MetaData attribute.
public static string ToName(this Enum value) {
var attribute = value.GetAttribute<DescriptionAttribute>();
return attribute == null ? value.ToString() : attribute.Description;
}
}
This solution creates a pair of extension methods on Enum. The first allows you to use reflection to retrieve any attribute associated with your value. The second specifically calls retrieves the DescriptionAttribute and returns it's Description value.
As an example, consider using the DescriptionAttribute attribute from System.ComponentModel
using System.ComponentModel;
public enum Days {
[Description("Sunday")]
Sun,
[Description("Monday")]
Mon,
[Description("Tuesday")]
Tue,
[Description("Wednesday")]
Wed,
[Description("Thursday")]
Thu,
[Description("Friday")]
Fri,
[Description("Saturday")]
Sat
}
To use the above extension method, you would now simply call the following:
Console.WriteLine(Days.Mon.ToName());
or
var day = Days.Mon;
Console.WriteLine(day.ToName());
In addition to AdamCrawford response, I've further created a more specialized extension methods that feed of it to get the description.
public static string GetAttributeDescription(this Enum enumValue)
{
var attribute = enumValue.GetAttributeOfType<DescriptionAttribute>();
return attribute == null ? String.Empty : attribute.Description;
}
hence, to get the description, you could either use the original extension method as
string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description
or you could simply call the the extension method here as:
string desc = myEnumVariable.GetAttributeDescription();
Which should hopefully make your code a bit more readable.
Fluent one liner...
Here I'm using the DisplayAttribute which contains both the Name and Description properties.
public static DisplayAttribute GetDisplayAttributesFrom(this Enum enumValue, Type enumType)
{
return enumType.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>();
}
Example
public enum ModesOfTransport
{
[Display(Name = "Driving", Description = "Driving a car")] Land,
[Display(Name = "Flying", Description = "Flying on a plane")] Air,
[Display(Name = "Sea cruise", Description = "Cruising on a dinghy")] Sea
}
void Main()
{
ModesOfTransport TransportMode = ModesOfTransport.Sea;
DisplayAttribute metadata = TransportMode.GetDisplayAttributesFrom(typeof(ModesOfTransport));
Console.WriteLine("Name: {0} \nDescription: {1}", metadata.Name, metadata.Description);
}
Output
Name: Sea cruise
Description: Cruising on a dinghy
Here is code to get information from a Display attribute. It uses a generic method to retrieve the attribute. If the attribute is not found it converts the enum value to a string with pascal/camel case converted to title case (code obtained here)
public static class EnumHelper
{
// Get the Name value of the Display attribute if the
// enum has one, otherwise use the value converted to title case.
public static string GetDisplayName<TEnum>(this TEnum value)
where TEnum : struct, IConvertible
{
var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
return attr == null ? value.ToString().ToSpacedTitleCase() : attr.Name;
}
// Get the ShortName value of the Display attribute if the
// enum has one, otherwise use the value converted to title case.
public static string GetDisplayShortName<TEnum>(this TEnum value)
where TEnum : struct, IConvertible
{
var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
return attr == null ? value.ToString().ToSpacedTitleCase() : attr.ShortName;
}
/// <summary>
/// Gets an attribute on an enum field value
/// </summary>
/// <typeparam name="TEnum">The enum type</typeparam>
/// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
/// <param name="value">The enum value</param>
/// <returns>The attribute of type T that exists on the enum value</returns>
private static T GetAttributeOfType<TEnum, T>(this TEnum value)
where TEnum : struct, IConvertible
where T : Attribute
{
return value.GetType()
.GetMember(value.ToString())
.First()
.GetCustomAttributes(false)
.OfType<T>()
.LastOrDefault();
}
}
And this is the extension method for strings for converting to title case:
/// <summary>
/// Converts camel case or pascal case to separate words with title case
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string ToSpacedTitleCase(this string s)
{
//https://stackoverflow.com/a/155486/150342
CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
TextInfo textInfo = cultureInfo.TextInfo;
return textInfo
.ToTitleCase(Regex.Replace(s,
"([a-z](?=[A-Z0-9])|[A-Z](?=[A-Z][a-z]))", "$1 "));
}
Get the dictionary from enum.
public static IDictionary<string, int> ToDictionary(this Type enumType)
{
return Enum.GetValues(enumType)
.Cast<object>()
.ToDictionary(v => ((Enum)v).ToEnumDescription(), k => (int)k);
}
Now call this like...
var dic = typeof(ActivityType).ToDictionary();
EnumDecription Ext Method
public static string ToEnumDescription(this Enum en) //ext method
{
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();
}
public enum ActivityType
{
[Description("Drip Plan Email")]
DripPlanEmail = 1,
[Description("Modification")]
Modification = 2,
[Description("View")]
View = 3,
[Description("E-Alert Sent")]
EAlertSent = 4,
[Description("E-Alert View")]
EAlertView = 5
}
I this answer to setup a combo box from an enum attributes which was great.
I then needed to code the reverse so that I can get the selection from the box and return the enum in the correct type.
I also modified the code to handle the case where an attribute was missing
For the benefits of the next person, here is my final solution
public static class Program
{
static void Main(string[] args)
{
// display the description attribute from the enum
foreach (Colour type in (Colour[])Enum.GetValues(typeof(Colour)))
{
Console.WriteLine(EnumExtensions.ToName(type));
}
// Get the array from the description
string xStr = "Yellow";
Colour thisColour = EnumExtensions.FromName<Colour>(xStr);
Console.ReadLine();
}
public enum Colour
{
[Description("Colour Red")]
Red = 0,
[Description("Colour Green")]
Green = 1,
[Description("Colour Blue")]
Blue = 2,
Yellow = 3
}
}
public static class EnumExtensions
{
// This extension method is broken out so you can use a similar pattern with
// other MetaData elements in the future. This is your base method for each.
public static T GetAttribute<T>(this Enum value) where T : Attribute
{
var type = value.GetType();
var memberInfo = type.GetMember(value.ToString());
var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
// check if no attributes have been specified.
if (((Array)attributes).Length > 0)
{
return (T)attributes[0];
}
else
{
return null;
}
}
// This method creates a specific call to the above method, requesting the
// Description MetaData attribute.
public static string ToName(this Enum value)
{
var attribute = value.GetAttribute<DescriptionAttribute>();
return attribute == null ? value.ToString() : attribute.Description;
}
/// <summary>
/// Find the enum from the description attribute.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="desc"></param>
/// <returns></returns>
public static T FromName<T>(this string desc) where T : struct
{
string attr;
Boolean found = false;
T result = (T)Enum.GetValues(typeof(T)).GetValue(0);
foreach (object enumVal in Enum.GetValues(typeof(T)))
{
attr = ((Enum)enumVal).ToName();
if (attr == desc)
{
result = (T)enumVal;
found = true;
break;
}
}
if (!found)
{
throw new Exception();
}
return result;
}
}
}
Performance matters
If you want better performance this is the way to go:
public static class AdvancedEnumExtensions
{
/// <summary>
/// Gets the custom attribute <typeparamref name="T"/> for the enum constant, if such a constant is defined and has such an attribute; otherwise null.
/// </summary>
public static T GetCustomAttribute<T>(this Enum value) where T : Attribute
{
return GetField(value)?.GetCustomAttribute<T>(inherit: false);
}
/// <summary>
/// Gets the FieldInfo for the enum constant, if such a constant is defined; otherwise null.
/// </summary>
public static FieldInfo GetField(this Enum value)
{
ulong u64 = ToUInt64(value);
return value
.GetType()
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
.Where(f => ToUInt64(f.GetRawConstantValue()) == u64)
.FirstOrDefault();
}
/// <summary>
/// Checks if an enum constant is defined for this enum value
/// </summary>
public static bool IsDefined(this Enum value)
{
return GetField(value) != null;
}
/// <summary>
/// Converts the enum value to UInt64
/// </summary>
public static ulong ToUInt64(this Enum value) => ToUInt64((object)value);
private static ulong ToUInt64(object value)
{
switch (Convert.GetTypeCode(value))
{
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
return unchecked((ulong)Convert.ToInt64(value, CultureInfo.InvariantCulture));
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Char:
case TypeCode.Boolean:
return Convert.ToUInt64(value, CultureInfo.InvariantCulture);
default: throw new InvalidOperationException("UnknownEnumType");
}
}
}
Why does this have better performance?
Because the built-in methods all use code very similar to this except they also run a bunch of other code we don't care about. C#'s Enum code is quite horrible in general.
The above code has been Linq-ified and streamlined so it only contains the bits we care about.
Why is the built-in code slow?
First regarding Enum.ToString() -vs- Enum.GetName(..)
Always use the latter. (Or better yet neither, as will become clear below.)
ToString() uses the latter internally, but again, also does a bunch of other stuff we don't want, e.g. tries to combine flags, print out numbers etc. We are only interested in constants defined inside the enum.
Enum.GetName in turn gets all fields, creates a string array for all names, uses the above ToUInt64 on all of their RawConstantValues to create an UInt64 array of all values, sorts both arrays according to the UInt64 value, and finally gets the name from the name-array by doing a BinarySearch in the UInt64-array to find the index of the value we wanted.
...and then we throw the fields and the sorted arrays away use that name to find the field again.
One word: "Ugh!"
For some programmer humor, a one liner as a joke:
public static string GetDescription(this Enum value) => value.GetType().GetMember(value.ToString()).First().GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute ? attribute.Description : string.Empty;
In a more readable form:
using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
public static class EnumExtensions
{
// get description from enum:
public static string GetDescription(this Enum value)
{
return value.GetType().
GetMember(value.ToString()).
First().
GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute
? attribute.Description
: throw new Exception($"Enum member '{value.GetType()}.{value}' doesn't have a [DescriptionAttribute]!");
}
// get enum from description:
public static T GetEnum<T>(this string description) where T : Enum
{
foreach (FieldInfo fieldInfo in typeof(T).GetFields())
{
if (fieldInfo.GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute && attribute.Description == description)
return (T)fieldInfo.GetRawConstantValue();
}
throw new Exception($"Enum '{typeof(T)}' doesn't have a member with a [DescriptionAttribute('{description}')]!");
}
}
Here's the .NET Core version of AdamCrawford's answer, using System.Reflection.TypeExtensions;
public static class EnumHelper
{
/// <summary>
/// Gets an attribute on an enum field value
/// </summary>
/// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
/// <param name="enumVal">The enum value</param>
/// <returns>The attribute of type T that exists on the enum value</returns>
/// <example>string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;</example>
public static T GetAttributeOfType<T>(this Enum enumVal) where T : System.Attribute
{
var type = enumVal.GetType();
var memInfo = type.GetMember(enumVal.ToString());
IEnumerable<Attribute> attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
return (T)attributes?.ToArray()[0];
}
}
Adding my solution for Net Framework and NetCore.
I used this for my Net Framework implementation:
public static class EnumerationExtension
{
public static string Description( this Enum value )
{
// get attributes
var field = value.GetType().GetField( value.ToString() );
var attributes = field.GetCustomAttributes( typeof( DescriptionAttribute ), false );
// return description
return attributes.Any() ? ( (DescriptionAttribute)attributes.ElementAt( 0 ) ).Description : "Description Not Found";
}
}
This doesn't work for NetCore so I modified it to do this:
public static class EnumerationExtension
{
public static string Description( this Enum value )
{
// get attributes
var field = value.GetType().GetField( value.ToString() );
var attributes = field.GetCustomAttributes( false );
// Description is in a hidden Attribute class called DisplayAttribute
// Not to be confused with DisplayNameAttribute
dynamic displayAttribute = null;
if (attributes.Any())
{
displayAttribute = attributes.ElementAt( 0 );
}
// return description
return displayAttribute?.Description ?? "Description Not Found";
}
}
Enumeration Example:
public enum ExportTypes
{
[Display( Name = "csv", Description = "text/csv" )]
CSV = 0
}
Sample Usage for either static added:
var myDescription = myEnum.Description();
If your enum contains a value like Equals you might bump into a few bugs using some extensions in a lot of answers here. This is because it is normally assumed that typeof(YourEnum).GetMember(YourEnum.Value) would return only one value, which is the MemberInfo of your enum. Here's a slightly safer version Adam Crawford's answer.
public static class AttributeExtensions
{
#region Methods
public static T GetAttribute<T>(this Enum enumValue) where T : Attribute
{
var type = enumValue.GetType();
var memberInfo = type.GetMember(enumValue.ToString());
var member = memberInfo.FirstOrDefault(m => m.DeclaringType == type);
var attribute = Attribute.GetCustomAttribute(member, typeof(T), false);
return attribute is T ? (T)attribute : null;
}
#endregion
}
Model
The model in which we fill our values
public class MemberTypeModel : IDto
{
public string MemberAttributeName { get; set; }
public string MemberName { get; set; }
public int MemberValue { get; set; }
}
Enum
Our target is the enum
public enum MemberType
{
[FieldText("Yönetim Kurul Üyesi")]
BoardManager = 0,
[FieldText("Temsilci")]
Representative = 1,
[FieldText("Üye")]
Member = 2
}
Helper Method
The helper method we will use to fetch the custom attribute object
public T GetMemberCustomText<T>(MemberType memberType) where T : Attribute
{
var enumType = memberType.GetType();
var name = Enum.GetName(enumType, memberType);
return enumType.GetField(name).GetCustomAttributes(false).OfType<T>().SingleOrDefault();
}
Get Method
First we pull enum values and cast them to enum type. Then, with the Linq selection query we know;
MemberAttributeName field with helper method,
MemberName field with Enum.GetName method,
Casting the MemberValue field to an int type as well,
We fill it out and turn it into a list.
public List<MemberTypeModel> GetMemberTypes()
{
var memberTypes = Enum.GetValues(typeof(MemberType))
.Cast<MemberType>()
.Select(et => new MemberTypeModel
{
MemberAttributeName = GetMemberCustomText<FieldText>(et).Text,
MemberName = Enum.GetName(et.GetType(), et),
MemberValue = (int)et
}).ToList();
return memberTypes;
}
I implemented this extension method to get the description from enum values. It works for all kind of enums.
public static class EnumExtension
{
public static string ToDescription(this System.Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}
}
Taking advantage of some of the newer C# language features, you can reduce the line count:
public static TAttribute GetEnumAttribute<TAttribute>(this Enum enumVal) where TAttribute : Attribute
{
var memberInfo = enumVal.GetType().GetMember(enumVal.ToString());
return memberInfo[0].GetCustomAttributes(typeof(TAttribute), false).OfType<TAttribute>().FirstOrDefault();
}
public static string GetEnumDescription(this Enum enumValue) => enumValue.GetEnumAttribute<DescriptionAttribute>()?.Description ?? enumValue.ToString();
Bryan Rowe and AdamCrawford thanks for your answers!
But if somebody need method for get Discription (not extension) you can use it:
string GetEnumDiscription(Enum EnumValue)
{
var type = EnumValue.GetType();
var memInfo = type.GetMember(EnumValue.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
return (attributes.Length > 0) ? ((DescriptionAttribute)attributes[0]).Description : null;
}
This extension method will obtain a string representation of an enum value using its XmlEnumAttribute. If no XmlEnumAttribute is present, it falls back to enum.ToString().
public static string ToStringUsingXmlEnumAttribute<T>(this T enumValue)
where T: struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
string name;
var type = typeof(T);
var memInfo = type.GetMember(enumValue.ToString());
if (memInfo.Length == 1)
{
var attributes = memInfo[0].GetCustomAttributes(typeof(System.Xml.Serialization.XmlEnumAttribute), false);
if (attributes.Length == 1)
{
name = ((System.Xml.Serialization.XmlEnumAttribute)attributes[0]).Name;
}
else
{
name = enumValue.ToString();
}
}
else
{
name = enumValue.ToString();
}
return name;
}
And if you want the full list of names you can do something like
typeof (PharmacyConfigurationKeys).GetFields()
.Where(x => x.GetCustomAttributes(false).Any(y => typeof(DescriptionAttribute) == y.GetType()))
.Select(x => ((DescriptionAttribute)x.GetCustomAttributes(false)[0]).Description);
public enum DataFilters
{
[Display(Name= "Equals")]
Equals = 1,// Display Name and Enum Name are same
[Display(Name= "Does Not Equal")]
DoesNotEqual = 2, // Display Name and Enum Name are different
}
Now it will produce error in this case 1 "Equals"
public static string GetDisplayName(this Enum enumValue)
{
var enumMember = enumValue.GetType().GetMember(enumValue.ToString()).First();
return enumMember.GetCustomAttribute<DisplayAttribute>() != null ? enumMember.GetCustomAttribute<DisplayAttribute>().Name : enumMember.Name;
}
so if it is same return enum name rather than display name because
enumMember.GetCustomAttribute()
gets null if displayname and enum name are same.....
The NuGet package Enums.Net has good support for this:
var value = FunkyAttributesEnum.NameWithoutSpaces1;
string description = value.AsString(EnumFormat.Description); // => "Name With Spaces1"
The package is simple, intuitive, and complete.
It's type-safe and has cache to avoid recurring reflection.
The GitHub repository has more information, including the limitations of the native Enum and a demo of functionality:
Getting attributes;
Flag operations;
Enum formats (for ToString or to parse the enum from string);
Rich iteration of all values with Enums.GetMembers<MyEnum>();
Etc.
Alternatively, you could do the following:
Dictionary<FunkyAttributesEnum, string> description = new Dictionary<FunkyAttributesEnum, string>()
{
{ FunkyAttributesEnum.NameWithoutSpaces1, "Name With Spaces1" },
{ FunkyAttributesEnum.NameWithoutSpaces2, "Name With Spaces2" },
};
And get the description with the following:
string s = description[FunkyAttributesEnum.NameWithoutSpaces1];
In my opinion this is a more efficient way of doing what you want to accomplish, as no reflection is needed..
Guys if it helps I will share with you my solution:
Definition of Custom attribute:
[AttributeUsage(AttributeTargets.Field,AllowMultiple = false)]
public class EnumDisplayName : Attribute
{
public string Name { get; private set; }
public EnumDisplayName(string name)
{
Name = name;
}
}
Now because I needed it inside of HtmlHelper definition of HtmlHelper Extension:
public static class EnumHelper
{
public static string EnumDisplayName(this HtmlHelper helper,EPriceType priceType)
{
//Get every fields from enum
var fields = priceType.GetType().GetFields();
//Foreach field skipping 1`st fieldw which keeps currently sellected value
for (int i = 0; i < fields.Length;i++ )
{
//find field with same int value
if ((int)fields[i].GetValue(priceType) == (int)priceType)
{
//get attributes of found field
var attributes = fields[i].GetCustomAttributes(false);
if (attributes.Length > 0)
{
//return name of found attribute
var retAttr = (EnumDisplayName)attributes[0];
return retAttr.Name;
}
}
}
//throw Error if not found
throw new Exception("Błąd podczas ustalania atrybutów dla typu ceny allegro");
}
}
Hope it helps
Alternatively, you could do the following:
List<SelectListItem> selectListItems = new List<SelectListItem>();
foreach (var item in typeof(PaymentTerm).GetEnumValues())
{
var type = item.GetType();
var name = type.GetField(item.ToString()).GetCustomAttributesData().FirstOrDefault()?.NamedArguments.FirstOrDefault().TypedValue.Value.ToString();
selectListItems.Add(new SelectListItem(name, type.Name));
}
This is how I solved it without using custom helpers or extensions with .NET core 3.1.
Class
public enum YourEnum
{
[Display(Name = "Suryoye means Arameans")]
SURYOYE = 0,
[Display(Name = "Oromoye means Syriacs")]
OROMOYE = 1,
}
Razor
#using Enumerations
foreach (var name in Html.GetEnumSelectList(typeof(YourEnum)))
{
<h1>#name.Text</h1>
}
I have created an extension method that will return description of all the elements in an enum in C#.
public static List<string> GetAllEnumDescriptions(this Type enumType)
{
try
{
var enumList = Enum.GetValues(enumType).Cast<Enum>().ToList();
List<string> result = new List<string>();
foreach (var enumItem in enumList)
{
result.Add(enumItem.EnumDescription());
}
return result;
}
catch (Exception ex)
{
return new List<string>();
}
}
This method will add the description of the elements in an enum using the inbuilt EnumDescription() extension method.

Is it possible to add custom properties to c# enum object?

Using c# Is it possible using to associate properties for each enum items?
I have used the Description Attribute to add English description to an enum item.
To add English description to each item I have done the following
public enum MyEnum
{
[Description("My First Item")]
First,
[Description("My Second Item")]
Second,
[Description("My Third Item")]
Third
}
Then I added an extension method to my enum called GetDescription() which allows me to get the description like so
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 name;
}
However, it will help me a lot if I am able to assign a class or construct a new object.
Is it possible/How can I do something like the follow?
public enum MyEnum
{
[Description("My First Item"), new { IsFirst = true, UnitType = 1}]
First
}
or using a class
public enum MyEnum
{
[Description("My First Item"), new MyCustomClass(true, 1)]
First
}
You can decorate elements with custom Attributes. Those can contain nearly anything you want.
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class DescriptorAttribute : Attribute
{
public bool IsFirst { get; }
public int UnitType { get; }
public DescriptorAttribute(bool isFirst, int unitType)
{
IsFirst = isFirst;
UnitType = unitType;
}
}
You would use this as follows:
public enum Test
{
[Descriptor(isFirst: true, unitType: 2)]
Element
}
you already have the code to read this attribute in your question.
You can create yet another extention method for this.
public static object Create(this MyEnum enum)
{
switch (enum)
{
case MyEnum.First:
return new { IsFirst = true, UnitType = 1}];
case MyEnum.Second:
return new ...
default:
...
}
}
then use it like so:
dynamic first = MyEnum.First.Create();
var isFirst = first.IsFirst;
but you really should consider creating a factory to create your objects.

Generic enum constraint

I have inherited a web api that has lots of enums defined in code, I want to convert them to a view-model class called EnumView so they can be serialized as below...
{Id: value, Name: enumName}
public class EnumView
{
public int Id { get; set; }
public string Name { get; set; }
}
Upon restricting the Generic class to the enum type, I get the warning
Constraint cannot be special class 'System.Enum'
This is the generic converter that I was going to use...
public class EnumViewConverter<T> where T : Enum
{
public static List<EnumView> ConvertToView()
{
List<EnumView> enumViews = new List<EnumView>();
T[] enumValues = (T[])Enum.GetValues(typeof(T));
foreach (var enumValue in enumValues)
{
var enumView = new EnumView
{
Id = (int)enumValue,
Name = Enum.GetName(typeof(T), enumValue)
};
enumViews.Add(enumView);
}
return enumViews;
}
}
Without T being constrained to an enum, the following conversion doesn't compile...
Id = (int)enumValue,
Due to the issue around a lack of generic enum constraints, what's the best way to go about this?
You could use : Id = Convert.ToInt32(enumValue) instead of the casting (int)
And if you want to add some 'constraint' to check the type at the compilation you could set 'where T : struct' it will at least prevent to set class type.
In the end I used...
public static class EnumViewConverter<T> where T : struct
{
public static List<EnumView> ConvertToView()
{
if (!typeof(T).IsEnum) throw new ArgumentException("T must be an enumerated type");
List<EnumView> enumViews = new List<EnumView>();
T[] enumValues = (T[])Enum.GetValues(typeof(T));
foreach (var enumValue in enumValues)
{
var enumView = new EnumView
{
Id = Convert.ToInt32(enumValue),
Name = Enum.GetName(typeof(T), enumValue)
};
enumViews.Add(enumView);
}
return enumViews;
}
}
Called by...
var views = EnumViewConverter<FooBarEnum>.ConvertToView();
Thanks for all the help, could have sworn I tried this earlier:(
To expand on my earlier comment, the technique described in this answer uses a nested class with a generic parameter dependent on its parent class to emulate generic Enum constraints. You could use this approach here:
public abstract class ConverterClassUtils<TClass>
where TClass : class
{
public class ViewConverter<TInner> where TInner : struct, TClass
{
public static List<EnumView> ConvertToView()
{
List<EnumView> enumViews = new List<EnumView>();
TInner[] enumValues = (TInner[])Enum.GetValues(typeof(TInner));
foreach (var enumValue in enumValues)
{
var enumView = new EnumView
{
Id = (int)(object)enumValue,
Name = Enum.GetName(typeof(TInner), enumValue)
};
enumViews.Add(enumView);
}
return enumViews;
}
}
}
public class EnumConverter : ConverterClassUtils<Enum> { }
then the following compiles:
var view = EnumConverter.ViewConverter<SomeEnum>.ConvertToView();
while this does not:
var view = EnumConverter.ViewConverter<int>.ConvertToView();

Get class properties in C# (whitout instantiating it)

I've a class "TradingStrategy", with n subclasses ("Strategy1, Strategy2 etc...").
I've a simple UI from which i can choose a subclass (I've got all the subclasses of the "TradingStrategy" class pretty easily).
What i want now is to print (in a datagridview, listbox, combobox, doesn't matter) all the public parameters of the choosen subclass.
I would prefer not to instantiate the subclasses.
namespace BackTester
{
class TradingStrategy
{
public string Name;
}
class MA_Test : TradingStrategy
{
new public string Name = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name;
public int len = 12;
public float lots = 0.1F;
public bool trendFollow = true;
public MA_Test()
{
}
}
class MA_Test2 : TradingStrategy
{
new public string Name = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name;
public int len = 24;
public float lots = 0.1F;
public bool trendFollow = true;
public MA_Test2()
{
}
}
}
With this code i can insert into a combo box every subclass of "TradingStrategy"
var type = typeof(TradingStrategy);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
foreach (var t in types){
if (t.Name == "TradingStrategy") continue;
boxStrategy.Items.Add(t.Name);
}
I wanna be able to, from the combobox.Text, get all the properties name and values of the corrisponding subclass.
I think I've read (and tried) every post here and in other forum. Many use reflections.
What is the simplest way to get those prop/values?
Thanks
Why not just create an interface ITradingStrategy:
public interface ITradingStrategy
{
string Name { get; }
int len { get; }
float lots { get; }
bool trendFollow { get; }
}
And have all classes inherit from the interface then pull values from interface.
As was mentioned in the comments, you have to instantiate an instance of the class in order to set some values on it.
To get the public fields/properties and their types without instantiating the objects, you can use reflection as follows:
private static Dictionary<string, Type> GetFields(Type t)
{
var fields = new Dictionary<string, Type>();
foreach (var memberInfo in t.GetMembers(BindingFlags.Instance | BindingFlags.Public))
{
var propertyInfo = memberInfo as PropertyInfo;
var fieldInfo = memberInfo as FieldInfo;
if (propertyInfo != null)
{
fields.Add(propertyInfo.Name, propertyInfo.PropertyType);
}
if (fieldInfo != null)
{
fields.Add(fieldInfo.Name, fieldInfo.FieldType);
}
}
return fields;
}
If you already have the object, you can get all the public fields/values with this method.
private static Dictionary<string, object> GetValues(FileInfo o)
{
var values = new Dictionary<string, object>();
foreach (var memberInfo in o.GetType().GetMembers(BindingFlags.Instance | BindingFlags.Public))
{
var propertyInfo = memberInfo as PropertyInfo;
var fieldInfo = memberInfo as FieldInfo;
if (propertyInfo != null)
{
values.Add(propertyInfo.Name, propertyInfo.GetValue(o, null));
}
if (fieldInfo != null)
{
values.Add(fieldInfo.Name, fieldInfo.GetValue(o));
}
}
return values;
}
The following code is a very slow way to get all the types which derive from a given type, due to the way that the CLR implements GetTypes() and the fact there could be thousands of unrelated types in your code which makes the haystack to search even bigger. The only time you should use this method is if you dynamically load assemblies at runtime containing object definitions that you need to load. Unfortunately there is no other way to get this information at runtime:
var type = typeof(TradingStrategy);
var subtypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => p != type && type.IsAssignableFrom(p));
I would recommend that you store this list of types somewhere in your code, e.g. in an array, and iterate over it when you need to know all of your strategies:
private static readonly Type[] TradingStrategies =
{
typeof(Strategy1),
typeof(Strategy2),
typeof(Strategy3),
};
After reading Erik's answer. If you will never instantiate these classes, you could store this data in a configuration file, and use something like JSON.net to read it, or if you don't want to use an external library, XmlSerializer would work as well. In this case you would store each MATest as a Dictionary (which lends itself nicely to JSON.net's JObject. Using JSON.net, you would have a configuration file that looks like:
[
{
"MA_Test": {
"len": 12,
"lots": 0.1,
"trendFollow": true
},
"MA_Test2": {
"len": 24,
"lots": 0.1,
"trendFollow": true
}
}
]
Then read it with code that looks like:
public JObject ReadConfig(string configPath)
{
using (var filestream = File.Open(configPath, FileMode.Open))
using (var streamReader = new StreamReader(filestream))
using (var jsonTextReader = new JsonTextReader(streamReader))
{
var jsonSerializer = new JsonSerializer();
return jsonSerializer.Deserialize<JObject>(jsonTextReader);
}
}
Thank you all for you answers.
The simplest way I found to get the properties from an indirected instantiated class is this:
var strategy = activator.CreateInstance(Type.GetType("BackTester."+boxStrategy.Text));
foreach (FieldInfo prop in strategy.GetType().GetFields(BindingFlags.Public
| BindingFlags.Instance))
{
listBox1.Items.Add(prop.ToString() + " " + prop.GetValue(strategy));
}
Based on the code you've provided, there is no reason for there to be separate classes for each MA_Test (X DO NOT use underscores, hyphens, or any other nonalphanumeric characters.). Instead these should be the same class with different properties (not fields).
class TradingStrategy
{
public string Name { get; set; }
}
class MATest : TradingStrategy
{
// this is not needed if it is inherited by TradingStragegy
// You should be getting a warning that you are hiding
// the field/property
// public string Name { get; set; }
// Should probably be more descriptive
// e.g. LengthInFeet...
public int Length { get; set; }
public float Lots { get; set; }
// I recommended boolean properties to be prefixed with
// Is, Can, Has, etc
public bool CanTrendFollow { get; set; }
}
// Somewhere Else...
var MATests = new List<MATest>()
{
new MATest()
{
Name = "MATest",
Length = 12,
Lots = 0.1F,
CanTrendFollow = true
},
new MATest()
{
Name = "MATest",
Length = 24,
Lots = 0.1F,
CanTrendFollow = true
},
}
Now instead of costly Reflection and Activator, just create the list classes once (manually, from config or even a database), and they can be used for whatever you need.

Enum Description to String

I have the following ENUM:
[Flags]
public enum DataFiat {
[Description("Público")]
Public = 1,
[Description("Filiado")]
Listed = 2,
[Description("Cliente")]
Client = 4
} // DataFiat
And I created an extension to get an Enum attribute:
public static T GetAttribute<T>(this Enum value) where T : Attribute {
T attribute;
MemberInfo info = value.GetType().GetMember(value.ToString()).FirstOrDefault();
if (info != null) {
attribute = (T)info.GetCustomAttributes(typeof(T), false).FirstOrDefault();
return attribute;
}
return null;
}
This works for non Flags Enums ... But when I have:
var x = DataFiat.Public | DataFiat.Listed;
var y = x.GetAttribute<Description>();
The value of y is null ...
I would like to get "Público, Filiado, Cliente" ... Just as ToString() works.
How can I change my extension to make this work?
Thank You
You can use this:
var values = x.ToString()
.Split(new[] { ", " }, StringSplitOptions.None)
.Select(v => (DataFiat)Enum.Parse(typeof(DataFiat), v));
To get the individual values. Then get the attribute values of them.
Something like this:
var y2 = values.GetAttributes<DescriptionAttribute, DataFiat>();
public static T[] GetAttributes<T, T2>(this IEnumerable<T2> values) where T : Attribute
{
List<T> ts =new List<T>();
foreach (T2 value in values)
{
T attribute;
MemberInfo info = value.GetType().GetMember(value.ToString()).FirstOrDefault();
if (info != null)
{
attribute = (T)info.GetCustomAttributes(typeof(T), false).FirstOrDefault();
ts.Add(attribute);
}
}
return ts.ToArray();
}
in .NET CORE without any additional libraries you can do:
public enum Divisions
{
[Display(Name = "My Title 1")]
None,
[Display(Name = "My Title 2")]
First,
}
and to get the title:
using System.ComponentModel.DataAnnotations
using System.Reflection
string title = enumValue.GetType()?.GetMember(enumValue.ToString())?[0]?.GetCustomAttribute<DisplayAttribute>()?.Name;
I think you want to make something like that
using System;
public enum ArrivalStatus { Unknown=-3, Late=-1, OnTime=0, Early=1 };
public class Example
{
public static void Main()
{
int[] values = { -3, -1, 0, 1, 5, Int32.MaxValue };
foreach (var value in values)
{
ArrivalStatus status;
if (Enum.IsDefined(typeof(ArrivalStatus), value))
status = (ArrivalStatus) value;
else
status = ArrivalStatus.Unknown;
Console.WriteLine("Converted {0:N0} to {1}", value, status);
}
}
}
// The example displays the following output:
// Converted -3 to Unknown
// Converted -1 to Late
// Converted 0 to OnTime
// Converted 1 to Early
// Converted 5 to Unknown
// Converted 2,147,483,647 to Unknown
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
public static class Program
{
[Flags]
public enum DataFiat
{
[Description("Público")]
Public = 1,
[Description("Filiado")]
Listed = 2,
[Description("Cliente")]
Client = 4
}
public static ICollection<string> GetAttribute<T>(this Enum value)
{
var result = new Collection<string>();
var type = typeof(DataFiat);
foreach (var value1 in Enum.GetValues(type))
{
var memInfo = type.GetMember(value1.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)attributes[0]).Description;
result.Add(description);
}
return result;
}
static void Main(string[] args)
{
var x = DataFiat.Public | DataFiat.Listed;
var y = x.GetAttribute<DataFiat>();
var output = string.Join(" ", y.ToArray());
Console.WriteLine(output);
}
}
I have changed the T to ICollection but you can change it as you wish or you can merege the data within the method and return the string back.
I came up with a different solution based on my previous code. It can be used as follows:
DataFiat fiat = DataFiat.Public | DataFiat.Listed;
var b = fiat.ToString();
var c = fiat.GetAttributes<TextAttribute>();
var d = fiat.GetAttributes<TextAttribute, String>(x => String.Join(",", x.Select(y => y.Value)));
I think it becomes easy to use either to get the attributes or doing something with them.
What do you think?
Let me know if the code can be somehow improved. Here is the code:
public static List<T> GetAttributes<T>(this Enum value) where T : Attribute {
List<T> attributes = new List<T>();
IEnumerable<Enum> flags = Enum.GetValues(value.GetType()).Cast<Enum>().Where(value.HasFlag);
if (flags != null) {
foreach (Enum flag in flags) {
MemberInfo info = flag.GetType().GetMember(flag.ToString()).FirstOrDefault();
if (info != null)
attributes.Add((T)info.GetCustomAttributes(typeof(T), false).FirstOrDefault());
}
return attributes;
}
return null;
} // GetAttributes
public static Expected GetAttributes<T, Expected>(this Enum value, Func<List<T>, Expected> expression) where T : Attribute {
List<T> attributes = value.GetAttributes<T>();
if (attributes == null)
return default(Expected);
return expression(attributes);
} // GetAttributes

Categories