My enum consists of the following values:
private enum PublishStatusses{
NotCompleted,
Completed,
Error
};
I want to be able to output these values in a user friendly way though.
I don't need to be able to go from string to value again.
I use the Description attribute from the System.ComponentModel namespace. Simply decorate the enum:
private enum PublishStatusValue
{
[Description("Not Completed")]
NotCompleted,
Completed,
Error
};
Then use this code to retrieve it:
public static string GetDescription<T>(this T enumerationValue)
where T : struct
{
Type type = enumerationValue.GetType();
if (!type.IsEnum)
{
throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
}
//Tries to find a DescriptionAttribute for a potential friendly name
//for the enum
MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
if (memberInfo != null && memberInfo.Length > 0)
{
object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0)
{
//Pull out the description value
return ((DescriptionAttribute)attrs[0]).Description;
}
}
//If we have no description attribute, just return the ToString of the enum
return enumerationValue.ToString();
}
I do this with extension methods:
public enum ErrorLevel
{
None,
Low,
High,
SoylentGreen
}
public static class ErrorLevelExtensions
{
public static string ToFriendlyString(this ErrorLevel me)
{
switch(me)
{
case ErrorLevel.None:
return "Everything is OK";
case ErrorLevel.Low:
return "SNAFU, if you know what I mean.";
case ErrorLevel.High:
return "Reaching TARFU levels";
case ErrorLevel.SoylentGreen:
return "ITS PEOPLE!!!!";
default:
return "Get your damn dirty hands off me you FILTHY APE!";
}
}
}
Maybe I'm missing something, but what's wrong with Enum.GetName?
public string GetName(PublishStatusses value)
{
return Enum.GetName(typeof(PublishStatusses), value)
}
edit: for user-friendly strings, you need to go through a .resource to get internationalisation/localisation done, and it would arguably be better to use a fixed key based on the enum key than a decorator attribute on the same.
I created a reverse extension method to convert the description back into an enum value:
public static T ToEnumValue<T>(this string enumerationDescription) where T : struct
{
var type = typeof(T);
if (!type.IsEnum)
throw new ArgumentException("ToEnumValue<T>(): Must be of enum type", "T");
foreach (object val in System.Enum.GetValues(type))
if (val.GetDescription<T>() == enumerationDescription)
return (T)val;
throw new ArgumentException("ToEnumValue<T>(): Invalid description for enum " + type.Name, "enumerationDescription");
}
The easiest solution here is to use a custom extension method (in .NET 3.5 at least - you can just convert it into a static helper method for earlier framework versions).
public static string ToCustomString(this PublishStatusses value)
{
switch(value)
{
// Return string depending on value.
}
return null;
}
I am assuming here that you want to return something other than the actual name of the enum value (which you can get by simply calling ToString).
That other post is Java. You can't put methods in Enums in C#.
just do something like this:
PublishStatusses status = ...
String s = status.ToString();
If you want to use different display values for your enum values, you could use Attributes and Reflection.
Some other more primitive options that avoid classes/reference types:
Array method
Nested struct method
Array method
private struct PublishStatusses
{
public static string[] Desc = {
"Not Completed",
"Completed",
"Error"
};
public enum Id
{
NotCompleted = 0,
Completed,
Error
};
}
Usage
string desc = PublishStatusses.Desc[(int)PublishStatusses.Id.Completed];
Nested struct method
private struct PublishStatusses
{
public struct NotCompleted
{
public const int Id = 0;
public const string Desc = "Not Completed";
}
public struct Completed
{
public const int Id = 1;
public const string Desc = "Completed";
}
public struct Error
{
public const int Id = 2;
public const string Desc = "Error";
}
}
Usage
int id = PublishStatusses.NotCompleted.Id;
string desc = PublishStatusses.NotCompleted.Desc;
Update (03/09/2018)
A hybrid of Extension Methods and the first technique above.
I prefer enums to be defined where they "belong" (closest to their source of origin and not in some common, global namespace).
namespace ViewModels
{
public class RecordVM
{
//public enum Enum { Minutes, Hours }
public struct Enum
{
public enum Id { Minutes, Hours }
public static string[] Name = { "Minute(s)", "Hour(s)" };
}
}
}
The extension method seems suited for a common area, and the "localized" definition of the enum now makes the extension method more verbose.
namespace Common
{
public static class EnumExtensions
{
public static string Name(this RecordVM.Enum.Id id)
{
return RecordVM.Enum.Name[(int)id];
}
}
}
A usage example of the enum and it's extension method.
namespace Views
{
public class RecordView
{
private RecordDataFieldList<string, string> _fieldUnit;
public RecordView()
{
_fieldUnit.List = new IdValueList<string, string>
{
new ListItem<string>((int)RecordVM.Enum.Id.Minutes, RecordVM.Enum.Id.Minutes.Name()),
new ListItem<string>((int)RecordVM.Enum.Id.Hours, RecordVM.Enum.Id.Hours.Name())
};
}
private void Update()
{
RecordVM.Enum.Id eId = DetermineUnit();
_fieldUnit.Input.Text = _fieldUnit.List.SetSelected((int)eId).Value;
}
}
}
Note: I actually decided to eliminate the Enum wrapper (and Name array), since it's best that the name strings come from a resource (ie config file or DB) instead of being hard-coded, and because I ended up putting the extension method in the ViewModels namespace (just in a different, "CommonVM.cs" file). Plus the whole .Id thing becomes distracting and cumbersome.
namespace ViewModels
{
public class RecordVM
{
public enum Enum { Minutes, Hours }
//public struct Enum
//{
// public enum Id { Minutes, Hours }
// public static string[] Name = { "Minute(s)", "Hour(s)" };
//}
}
}
CommonVM.cs
//namespace Common
namespace ViewModels
{
public static class EnumExtensions
{
public static string Name(this RecordVM.Enum id)
{
//return RecordVM.Enum.Name[(int)id];
switch (id)
{
case RecordVM.Enum.Minutes: return "Minute(s)";
case RecordVM.Enum.Hours: return "Hour(s)";
default: return null;
}
}
}
}
A usage example of the enum and it's extension method.
namespace Views
{
public class RecordView
{
private RecordDataFieldList<string, string> _fieldUnit
public RecordView()
{
_fieldUnit.List = new IdValueList<string, string>
{
new ListItem<string>((int)RecordVM.Enum.Id.Minutes, RecordVM.Enum.Id.Minutes.Name()),
new ListItem<string>((int)RecordVM.Enum.Id.Hours, RecordVM.Enum.Id.Hours.Name())
};
}
private void Update()
{
RecordVM.Enum eId = DetermineUnit();
_fieldUnit.Input.Text = _fieldUnit.List.SetSelected((int)eId).Value;
}
}
}
The simplest way is just to include this extension class into your project, it will work with any enum in the project:
public static class EnumExtensions
{
public static string ToFriendlyString(this Enum code)
{
return Enum.GetName(code.GetType(), code);
}
}
Usage:
enum ExampleEnum
{
Demo = 0,
Test = 1,
Live = 2
}
...
ExampleEnum ee = ExampleEnum.Live;
Console.WriteLine(ee.ToFriendlyString());
You can use Humanizer package with Humanize Enums possiblity. An eaxample:
enum PublishStatusses
{
[Description("Custom description")]
NotCompleted,
AlmostCompleted,
Error
};
then you can use Humanize extension method on enum directly:
var st1 = PublishStatusses.NotCompleted;
var str1 = st1.Humanize(); // will result in Custom description
var st2 = PublishStatusses.AlmostCompleted;
var str2 = st2.Humanize(); // will result in Almost completed (calculated automaticaly)
public enum MyEnum
{
[Description("Option One")]
Option_One
}
public static string ToDescriptionString(this Enum This)
{
Type type = This.GetType();
string name = Enum.GetName(type, This);
MemberInfo member = type.GetMembers()
.Where(w => w.Name == name)
.FirstOrDefault();
DescriptionAttribute attribute = member != null
? member.GetCustomAttributes(true)
.Where(w => w.GetType() == typeof(DescriptionAttribute))
.FirstOrDefault() as DescriptionAttribute
: null;
return attribute != null ? attribute.Description : name;
}
With respect to Ray Booysen, there is a bug in the code: Enum ToString with user friendly strings
You need to account for multiple attributes on the enum values.
public static string GetDescription<T>(this object enumerationValue)
where T : struct
{
Type type = enumerationValue.GetType();
if (!type.IsEnum)
{
throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
}
//Tries to find a DescriptionAttribute for a potential friendly name
//for the enum
MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
if (memberInfo != null && memberInfo.Length > 0)
{
object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
{
//Pull out the description value
return ((DescriptionAttribute)attrs.Where(t=>t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description;
}
}
//If we have no description attribute, just return the ToString of the enum
return enumerationValue.ToString();
Instead of using an enum use a static class.
replace
private enum PublishStatuses{
NotCompleted,
Completed,
Error
};
with
private static class PublishStatuses{
public static readonly string NotCompleted = "Not Completed";
public static readonly string Completed = "Completed";
public static readonly string Error = "Error";
};
it will be used like this
PublishStatuses.NotCompleted; // "Not Completed"
Issue using the top "extension method" solutions:
A private enum is often used inside another class. The extension method solution is not valid there since it must be in it's own class. This solution can be private and embedded in another class.
Clean summary of the above suggestions with sample:
namespace EnumExtensions {
using System;
using System.Reflection;
public class TextAttribute : Attribute {
public string Text;
public TextAttribute( string text ) {
Text = text;
}//ctor
}// class TextAttribute
public static class EnumExtender {
public static string ToText( this Enum enumeration ) {
MemberInfo[] memberInfo = enumeration.GetType().GetMember( enumeration.ToString() );
if ( memberInfo != null && memberInfo.Length > 0 ) {
object[] attributes = memberInfo[ 0 ].GetCustomAttributes( typeof(TextAttribute), false );
if ( attributes != null && attributes.Length > 0 ) {
return ( (TextAttribute)attributes[ 0 ] ).Text;
}
}//if
return enumeration.ToString();
}//ToText
}//class EnumExtender
}//namespace
USAGE:
using System;
using EnumExtensions;
class Program {
public enum Appearance {
[Text( "left-handed" ) ]
Left,
[Text( "right-handed" ) ]
Right,
}//enum
static void Main( string[] args ) {
var appearance = Appearance.Left;
Console.WriteLine( appearance.ToText() );
}//Main
}//class
Use Enum.GetName
From the above link...
using System;
public class GetNameTest {
enum Colors { Red, Green, Blue, Yellow };
enum Styles { Plaid, Striped, Tartan, Corduroy };
public static void Main() {
Console.WriteLine("The 4th value of the Colors Enum is {0}", Enum.GetName(typeof(Colors), 3));
Console.WriteLine("The 4th value of the Styles Enum is {0}", Enum.GetName(typeof(Styles), 3));
}
}
// The example displays the following output:
// The 4th value of the Colors Enum is Yellow
// The 4th value of the Styles Enum is Corduroy
According to this documentation: https://learn.microsoft.com/pt-br/dotnet/api/system.enum.tostring?view=netframework-4.8
It is possible to just convert a enumerator to string using a format like this:
public enum Example
{
Example1,
Example2
}
Console.WriteLine(Example.Example1.ToString("g"));
//Outputs: "Example1"
You can see all the possible formats in this link: https://learn.microsoft.com/pt-br/dotnet/api/system.string?view=netframework-4.8
I happen to be a VB.NET fan, so here's my version, combining the DescriptionAttribute method with an extension method. First, the results:
Imports System.ComponentModel ' For <Description>
Module Module1
''' <summary>
''' An Enum type with three values and descriptions
''' </summary>
Public Enum EnumType
<Description("One")>
V1 = 1
' This one has no description
V2 = 2
<Description("Three")>
V3 = 3
End Enum
Sub Main()
' Description method is an extension in EnumExtensions
For Each v As EnumType In [Enum].GetValues(GetType(EnumType))
Console.WriteLine("Enum {0} has value {1} and description {2}",
v,
CInt(v),
v.Description
)
Next
' Output:
' Enum V1 has value 1 and description One
' Enum V2 has value 2 and description V2
' Enum V3 has value 3 and description Three
End Sub
End Module
Basic stuff: an enum called EnumType with three values V1, V2 and V3. The "magic" happens in the Console.WriteLine call in Sub Main(), where the last argument is simply v.Description. This returns "One" for V1, "V2" for V2, and "Three" for V3. This Description-method is in fact an extension method, defined in another module called EnumExtensions:
Option Strict On
Option Explicit On
Option Infer Off
Imports System.Runtime.CompilerServices
Imports System.Reflection
Imports System.ComponentModel
Module EnumExtensions
Private _Descriptions As New Dictionary(Of String, String)
''' <summary>
''' This extension method adds a Description method
''' to all enum members. The result of the method is the
''' value of the Description attribute if present, else
''' the normal ToString() representation of the enum value.
''' </summary>
<Extension>
Public Function Description(e As [Enum]) As String
' Get the type of the enum
Dim enumType As Type = e.GetType()
' Get the name of the enum value
Dim name As String = e.ToString()
' Construct a full name for this enum value
Dim fullName As String = enumType.FullName + "." + name
' See if we have looked it up earlier
Dim enumDescription As String = Nothing
If _Descriptions.TryGetValue(fullName, enumDescription) Then
' Yes we have - return previous value
Return enumDescription
End If
' Find the value of the Description attribute on this enum value
Dim members As MemberInfo() = enumType.GetMember(name)
If members IsNot Nothing AndAlso members.Length > 0 Then
Dim descriptions() As Object = members(0).GetCustomAttributes(GetType(DescriptionAttribute), False)
If descriptions IsNot Nothing AndAlso descriptions.Length > 0 Then
' Set name to description found
name = DirectCast(descriptions(0), DescriptionAttribute).Description
End If
End If
' Save the name in the dictionary:
_Descriptions.Add(fullName, name)
' Return the name
Return name
End Function
End Module
Because looking up description attributes using Reflection is slow, the lookups are also cached in a private Dictionary, that is populated on demand.
(Sorry for the VB.NET solution - it should be relatively straighforward to translate it to C#, and my C# is rusty on new subjects like extensions)
Even cleaner summary:
using System;
using System.Reflection;
public class TextAttribute : Attribute
{
public string Text;
public TextAttribute(string text)
{
Text = text;
}
}
public static class EnumExtender
{
public static string ToText(this Enum enumeration)
{
var memberInfo = enumeration.GetType().GetMember(enumeration.ToString());
if (memberInfo.Length <= 0) return enumeration.ToString();
var attributes = memberInfo[0].GetCustomAttributes(typeof(TextAttribute), false);
return attributes.Length > 0 ? ((TextAttribute)attributes[0]).Text : enumeration.ToString();
}
}
Same usage as underscore describes.
In case you just want to add a whitespace between the words, it is as simple as
string res = Regex.Replace(PublishStatusses.NotCompleted, "[A-Z]", " $0").Trim();
This is an update to Ray Booysen's code that uses the generic GetCustomAttributes method and LINQ to make things a bit tidier.
/// <summary>
/// Gets the value of the <see cref="T:System.ComponentModel.DescriptionAttribute"/> on an struct, including enums.
/// </summary>
/// <typeparam name="T">The type of the struct.</typeparam>
/// <param name="enumerationValue">A value of type <see cref="T:System.Enum"/></param>
/// <returns>If the struct has a Description attribute, this method returns the description. Otherwise it just calls ToString() on the struct.</returns>
/// <remarks>Based on http://stackoverflow.com/questions/479410/enum-tostring/479417#479417, but useful for any struct.</remarks>
public static string GetDescription<T>(this T enumerationValue) where T : struct
{
return enumerationValue.GetType().GetMember(enumerationValue.ToString())
.SelectMany(mi => mi.GetCustomAttributes<DescriptionAttribute>(false),
(mi, ca) => ca.Description)
.FirstOrDefault() ?? enumerationValue.ToString();
}
I'm 7 years late for the party :-) But I'm sure this topic is visited frequently. So I wanted to add a little sugar to the coffee:
What about the "F" format string specifier?
PublishStatusses[] ps = Enum.GetValues<PublishStatusses>();
ps.ToList().ForEach(c => Console.Write($"{c:F} "));
There is no need for any explicit function call.
In fact there isn't even need for any format specifier.
In case of a variable assignment to a string, ToString() does the work:
string foo = PublishStatusses.Error.ToString(); // or ToString("F")
And if it is about to insert spaces between words of a CamelCase string, you can just use a regular expression:
Regex.Replace(foo, "(\\B[A-Z])", " $1")
For flags enum including.
public static string Description(this Enum value)
{
Type type = value.GetType();
List<string> res = new List<string>();
var arrValue = value.ToString().Split(',').Select(v=>v.Trim());
foreach (string strValue in arrValue)
{
MemberInfo[] memberInfo = type.GetMember(strValue);
if (memberInfo != null && memberInfo.Length > 0)
{
object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
{
res.Add(((DescriptionAttribute)attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description);
}
else
res.Add(strValue);
}
else
res.Add(strValue);
}
return res.Aggregate((s,v)=>s+", "+v);
}
Just use a static class that simulate an enum:
public static class PublishStatusses{
public const string NotCompleted = "Not Completed";
public const string Completed = "Completed";
public const string Error = "Error"
};
And to access the values, just use like an enum:
PublishStatusses.NotCompleted;
I use a generic class to store the enum/description pairs and a nested helper class to get the description.
The enum:
enum Status { Success, Fail, Pending }
The generic class:
Note: Since a generic class cannot be constrained by an enum I am constraining by struct instead and checking for enum in the constructor.
public class EnumX<T> where T : struct
{
public T Code { get; set; }
public string Description { get; set; }
public EnumX(T code, string desc)
{
if (!typeof(T).IsEnum) throw new NotImplementedException();
Code = code;
Description = desc;
}
public class Helper
{
private List<EnumX<T>> codes;
public Helper(List<EnumX<T>> codes)
{
this.codes = codes;
}
public string GetDescription(T code)
{
EnumX<T> e = codes.Where(c => c.Code.Equals(code)).FirstOrDefault();
return e is null ? "Undefined" : e.Description;
}
}
}
Usage:
EnumX<Status>.Helper StatusCodes = new EnumX<Status>.Helper(new List<EnumX<Status>>()
{
new EnumX<Status>(Status.Success,"Operation was successful"),
new EnumX<Status>(Status.Fail,"Operation failed"),
new EnumX<Status>(Status.Pending,"Operation not complete. Please wait...")
});
Console.WriteLine(StatusCodes.GetDescription(Status.Pending));
I think the best (and easiest) way to solve your problem is to write an Extension-Method for your enum:
public static string GetUserFriendlyString(this PublishStatusses status)
{
}
If you want something completely customizable, try out my solution here:
http://www.kevinwilliampang.com/post/Mapping-Enums-To-Strings-and-Strings-to-Enums-in-NET.aspx
Basically, the post outlines how to attach Description attributes to each of your enums and provides a generic way to map from enum to description.
Related
To seed type tables in Entity Framework Core, I am rewriting this same code in the function 'StopLightColorTypeList' for every database type table that I need seed. I'm looking to create a generic method.
modelBuilder.Entity<StopLightColorType>
().HasData(WLProgramSeed.StopLightColorTypeList());
The StopLightColorTypeList takes each enumeration member creates a new StopLightColorType object and adds it to the list before:
Setting the object ID property to the int value of the Enum
Setting the Name property to the string value of the Enum
I am looking to use generics in such a way where I can
Specify the enumeration type (in this case it's StopLightColorsEnum)
Specify the return type object (in this case it's StopLightColorType)
Specify what property to set for the ID (must be integer) (in this case it's StopLightColorID)
Specify what property to set for the name (must be a string) (in this case it's StopLightColorName)
Optionally specify a function to parse the enumeration name
using System;
using System.Collections.Generic;
using System.Linq;
namespace GenericEnumToTypeList
{
class Program
{
static void Main(string[] args)
{
List<StopLightColorType> stopLightColorTypes = EFTools.StopLightColorTypes();
foreach(var stopLightColorType in stopLightColorTypes)
{
Console.WriteLine("ID: {0} Name: {1}", stopLightColorType.StopLightColorID, stopLightColorType.StopLightColorName);
}
Console.ReadLine();
}
}
public enum StopLightColorsEnum
{
Red = 1,
Yellow = 2,
Green = 3
}
public class StopLightColorType
{
public StopLightColorsEnum StopLightColorID { get; set; }
public string StopLightColorName { get; set; }
}
public class EFTools
{
public static List<StopLightColorType> StopLightColorTypes()
{
List<StopLightColorType> stopLightColorTypes = new List<StopLightColorType>();
foreach(StopLightColorsEnum stopLightColor in System.Enum.GetValues(typeof(StopLightColorsEnum))
{
StopLightColorType stopLightColorType = new StopLightColorType
{
StopLightColorID = stopLightColor,
StopLightColorName = ParseCapitalizedEnumName(stopLightColor.ToString())
};
stopLightColorTypes.Add(stopLightColorType);
}
return stopLightColorTypes;
}
public static string ParseUnderScoreName(string stringName)
{
return stringName.Replace("_", " "); ;
}
public static string ParseCapitalizedEnumName(string enumName)
{
string typeName = enumName[0].ToString();
for(int i = 1; i <= enumName.Length; i++)
{
if(Char.ToUpper(enumName[i]) == enumName[i])
{
typeName = typeName + " " + enumName[i].ToString();
}
}
return typeName;
}
}
}
I re-write this code for each database type, I'm looking for a generic to take care of this operation.
The core function you need is this:
IEnumerable<TResult> ListEnumMembers<TEnum, TResult>(string valueName, string nameName)
where TEnum : System.Enum
{
var enumInfos = Enum.GetValues(typeof(TEnum)).Cast<int>()
.Zip(Enum.GetNames(typeof(TEnum)), (i, s) => (Value: i, Name: s));
var typ = typeof(TResult);
var piValue = typ.GetProperty(valueName);
var piName = typ.GetProperty(nameName);
return enumInfos.Select(i =>
{
var instance = (TResult)Activator.CreateInstance(typ);
piValue.SetValue(instance, i.Value);
piName.SetValue(instance, i.Name);
return instance;
});
}
With this generic result type...
class EnumInfo
{
public int Value { get; set; }
public string Name { get; set; }
}
...and this code:
var enumInfos = ListEnumMembers<DayOfWeek, EnumInfo>("Value", "Name").ToList();
You get this result:
Value
Name
0
Sunday
1
Monday
2
Tuesday
3
Wednesday
4
Thursday
5
Friday
6
Saturday
I guess this will put you on the right track. Of course the code needs a couple of checks for the property names and types.
I am building a model with Entity Framework and purchased responsive CSS.
The built in fixed icons comes with CSS. Like as follows (Name and Icon Class Value)
I need a way to keep the names of icons as fixed enums to access it from the VS intellisense. Currently we can't store as a entity table in entity framework (as it require relationship with tables difficult to maintain) and enum doesn't allows string type.
Code that did not work:
public sealed class IconType
{
public static readonly IconType Rupee_Icon = new IconType("rupee-icons");
public static readonly IconType Doller_Icon = new IconType("doller-icon");
private IconType(int EnumID,string EnumObjectValue)
{
IconValue = EnumObjectValue;
}
public string IconValue { get; private set; }
}
More code that did not work (CSS class names contains whitespaces like ui bell icon):
public enum Icon
{
NotSet=0,
Idea Icon=1,
Bell Icon =2
}
Is there any other ways to use names / objects as enums or constants in EF for easy intellisense in Visual Studio?
You could:
Omit the white spaces in the enums:
public enum Icon
{
NotSet = 0,
IdeaIcon = 1,
BellIcon = 2
}
Add a description or name (Or even some custom attribute) attributes to the enums:
public enum Icon
{
NotSet = 0,
[Description("ui idea icon")]
IdeaIcon = 1,
[Description("ui bell icon")]
BellIcon = 2
}
When needed get the description name. Example method to get the description attribute value:
public static string GetDescription<T>(this T enumerationValue)
where T : struct, IConvertible
{
var type = enumerationValue.GetType();
if (!type.IsEnum)
{
throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
}
// Tries to find a DescriptionAttribute for a potential friendly name for the enum
var memberInfo = type.GetMember(enumerationValue.ToString(CultureInfo.InvariantCulture));
if (memberInfo.Length > 0)
{
var attributes = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Length > 0)
{
// Pull out the description value
return ((DescriptionAttribute)attributes[0]).Description;
}
}
// If we have no description attribute, just return the ToString of the enum
return enumerationValue.ToString(CultureInfo.InvariantCulture);
}
Did you consider using string constants?
public static class IconType
{
public const string RUPEE_ICON = "rupee-icon";
public const string DOLLER_ICON = "doller-icon";
// ...
}
Store the icon's as plain old objects. Why make use of entity framework at all?
public static class Icons
{
public enum Type
{
IdeaIcon = 1,
BellIcon =2
}
public static Icon Get(Type type)
{
return IconCollection.Single(icon => icon.Type == type);
}
static IEnumerable<Icon> IconCollection
{
get
{
return new List<Icon>
{
new Icon(Type.IdeaIcon, "Idea Icon", "icon idea-icon"),
new Icon(Type.BellIcon, "Bell Icon", "icon bell-icon"),
};
}
}
public class Icon
{
public Icon(Type type, string description, string cssClass)
{
Type = type;
Description = description;
CssClass = cssClass;
}
public Type Type { get; private set; }
public string Description { get; private set; }
public string CssClass { get; private set; }
}
}
Use in code:
public class Class1
{
public void Method1()
{
var ideaIcon = Icons.Get(Icons.Type.IdeaIcon);
var x = ideaIcon.CssClass;
var y = ideaIcon.Description;
var bellIcon = Icons.Get(Icons.Type.BellIcon);
// etc...
}
}
Razor view:
#Icons.Get(Icons.Type.BellIcon).CssClass
If you needed to enumerate over the icon collection you could easily add another static accessor to the Icons class.
I have recently started a development in c# and want to use reflection in following situation.
If I have a Enum class as
Enum Operation
{
Read=0;
Write;
}
If I give input as
String str = "Operation.Write";
I shoud be able to get output as 1;
Or
if constants are defined like
const int Read=0;
const int Write=1;
If the input is
String str = "Read";
output should be 0
Please Help.
You can use Enum.Parse to have that functionality.
If we combine your proposals we can get something like this.
public static Operation getOperationByName(String name) {
return Enum.Parse(typeof(Operation),name);
}
Where the name should not be null and represent the name or position in enum ie
"Read" will return Operation.Rerad and "1" will return Operation.Write
Heres the complete code to also Get the type of the Enum through Reflection without hardcoding it. The ParseConstant Method is also generic, s.t. you can use if for every Type.
namespace MyNamgespace
{
public enum Operation
{
Read = 0,
Write
}
public class ClassWithConstants
{
public const int Read = 0;
public const int Write = 1;
}
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine((ParseEnum("Operation.Write")));
Console.WriteLine((ParseContant<ClassWithConstants>("Write")));
Console.ReadLine();
}
static int ParseEnum(string enumValue)
{
var typeName = enumValue.Split('.')[0];
var valueName = enumValue.Split('.')[1];
var enumType = Type.GetType(string.Format("MyNamespace.{0}", typeName));
var op = (Operation) Enum.Parse(enumType, valueName);
return (int)op;
}
static int ParseContant<T>(string constantName)
{
var type = typeof (T);
var field = type.GetField(constantName, BindingFlags.Static | BindingFlags.Public);
return (int)field.GetValue(null);
}
}
}
var name = Enum.GetName(typeof(Operation), Operation.Write) //name = 'Write'
var value = Enum.Parse(typeof(Operation), "Write") //value = Operation.Write
I have a class that parses in data from a comma delimited text file. I have an enum for the fields to help me parse data in easier. The class that parses all the records in holds public variables for each field, and of course their variable types. I need to get the type of these variables based on the enum given.
public enum DatabaseField : int
{
NumID1 = 1,
NumID2 = 2,
NumID3 = 3,
};
public class DataBaseRecordInfo
{
public long NumID1 { get; set; }
public int NumID2 { get; set; }
public short NumID3 { get; set; }
public static Type GetType(DatabaseField field)
{
Type type;
switch (field)
{
case DatabaseField.NumID1:
type = typeof(long);
break;
case DatabaseField.NumID2:
type = typeof(int);
break;
case DatabaseField.NumID3:
type = typeof(short);
break;
default:
type = typeof(int);
break;
}
return type;
}
};
NumID1, NumID2, NumID3 all get assigned within my constructor. However, I want to get these types without ever creating an instance of DataBaseRecordInfo. Right now my static method above would work, however, if I wanted to change the variable type, I would have to change it in 2 places. Is there a way to get around having to change this in both places and keep it as a static method?
If the name is always going to match exactly you can do this using reflection.
return typeof(DataBaseRecordInfo)
.GetProperty(field.ToString(), BindingFlags.Public | BindingFlags.Instance)
.PropertyType;
You could even cache these values in a dictionary, so if found, just return the dictionary entry, otherwise determine using reflection and cache the result.
Yes, you can use the names in the enum together with reflection on the DatabaseRecordInfo type to get the types you need.
This could be done like this:
public class DataBaseRecordInfo
{
public long NumID1 { get; set; }
public int NumID2 { get; set; }
public short NumID3 { get; set; }
public static Type GetType(DatabaseField field)
{
string name = field.ToString();
Type recordType = typeof (DataBaseRecordInfo);
var props = recordType.GetProperties();
var matchedProperty = props.Where(p => name == p.Name).FirstOrDefault();
if (matchedProperty == null)
return null; // We do not have a matching property.
return matchedProperty.PropertyType;
}
};
You will probably want to cache the result in a dictionary, since the reflection can be expensive performance-wise.
How about something like this:
public static Type GetType(DatabaseField field)
{
DataBaseRecordInfo dbri = new DataBaseRecordInfo();
switch (field)
{
case DatabaseField.NumID1:
return dbri.NumID1.GetType();
case DatabaseField.NumID2:
return dbri.NumID2.GetType();
case DatabaseField.NumID3:
return dbri.NumID3.GetType();
default:
return typeof(int);
}
}
I know you said without ever having to create an instance of DataBaseRecordInfo but I'm assuming you meant an instance outside of the static method. No one ever sees this instance.
If you want to bind enum value with some additional information you can use your own CustomAttribute.
Maybe you need something like this:
public class DatabaseTypeAttribute : Attribute
{
public DatabaseTypeAttribute(Type type)
{
Type = type;
}
public Type Type { get; private set; }
}
public enum DatabaseField : int
{
[DatabaseType(typeof(long))]
NumID1 = 1,
[DatabaseType(typeof(int))]
NumID2 = 2,
[DatabaseType(typeof(short))]
NumID3 = 3,
NumID4 = 4,
};
public static class DatabaseFieldHelper
{
public static Type GetDatabaseType(this DatabaseField field)
{
var attributes = (DatabaseTypeAttribute[])typeof(DatabaseField).GetField(Enum.GetName(typeof(DatabaseField), field))
.GetCustomAttributes(typeof(DatabaseTypeAttribute), false);
if (attributes.Length == 0)
return typeof(int); //returns default type
return attributes[0].Type;
}
}
//prints: NumID1 database type: System.Int64
Console.WriteLine("NumID1 database type: {0}", DatabaseField.NumID1.GetDatabaseType());
//prints: NumID2 database type: System.Int32
Console.WriteLine("NumID2 database type: {0}", DatabaseField.NumID2.GetDatabaseType());
//prints: NumID3 database type: System.Int16
Console.WriteLine("NumID3 database type: {0}", DatabaseField.NumID3.GetDatabaseType());
//prints: NumID4 database type: System.Int32
Console.WriteLine("NumID4 database type: {0}", DatabaseField.NumID4.GetDatabaseType());
What is the best way to localize enumeration descriptions in .net?
(See Adding descriptions to enumeration constants for enum description example)
Ideally I would like something that uses ResourceManager and resource files so it fits in with how other areas of the app are localized.
This is what I ended up going with, I didn't see the value in adding a custom attribute class to hold a resource key and then looking up into the resource files - why not just use the enums typename + value as a resource key?
using System;
using System.Resources;
using System.Reflection;
public class MyClass
{
enum SomeEnum {Small,Large};
private ResourceManager _resources = new ResourceManager("MyClass.myResources",
System.Reflection.Assembly.GetExecutingAssembly());
public string EnumDescription(Enum enumerator)
{
string rk = String.Format("{0}.{1}",enumerator.GetType(),enumerator);
string localizedDescription = _resources.GetString(rk);
if (localizedDescription == null)
{
// A localized string was not found so you can either just return
// the enums value - most likely readable and a good fallback.
return enumerator.ToString();
// Or you can return the full resourceKey which will be helpful when
// editing the resource files(e.g. MyClass+SomeEnum.Small)
// return resourceKey;
}
else
return localizedDescription;
}
void SomeRoutine()
{
// Looks in resource file for a string matching the key
// "MyClass+SomeEnum.Large"
string s1 = EnumDescription(SomeEnum.Large);
}
}
My solution, using native decription attribute:
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);
}
}
}
public static class EnumExtender
{
public static string GetLocalizedDescription(this Enum #enum)
{
if (#enum == null)
return null;
string description = #enum.ToString();
FieldInfo fieldInfo = #enum.GetType().GetField(description);
DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Any())
return attributes[0].Description;
return description;
}
}
The Enum declaration
public enum MyEnum
{
[LocalizedEnum("ResourceName", NameResourceType = typeof(ResourceType))]
Test = 0
}
Then call MyEnumInstance.GetLocalizedDescription()
there is an easy solution:
use LocalizedDescription attribute to pass a resource key.
[Serializable]
public class LocalizableDescriptionAttribute:DescriptionAttribute
{
public LocalizableDescriptionAttribute(string resourceKey)
:base(Resources.ResourceManager.GetString(resourceKey))
{ }
}
One way I did it once, was to add an extention method in the same namespace as an enum, which returned a string. In my case it was just hardcoded, but would be no problem getting them from a resource file.
public static string Describe(this SomeEnum e)
{
switch(e)
{
SomeEnum.A:
return "Some text from resourcefile";
SomeEnum.B:
return "Some other text from resourcefile";
...:
return ...;
}
}
Maybe not an extremly smooth or fancy solution, but it works =)
Replace #nairik's method with the following to add support for flags enums.
public static string GetLocalizedDescription(this Enum #enum)
{
if ( #enum == null )
return null;
StringBuilder sbRet = new StringBuilder();
string description = #enum.ToString();
var fields = description.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
foreach ( var field in fields )
{
FieldInfo fieldInfo = #enum.GetType().GetField(field);
DescriptionAttribute[] attributes = ( DescriptionAttribute[] )fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if ( attributes.Any() )
sbRet.AppendFormat("{0}, ", attributes[0].Description);
else
sbRet.AppendFormat("{0}, ", field);
}
if ( sbRet.Length > 2 )
sbRet.Remove(sbRet.Length - 2, 2);
return sbRet.ToString();
}
and replace NameResourceType in the attribute:
public Type NameResourceType
{
get
{
return _resourceType;
}
set
{
_resourceType = value;
_nameProperty = _resourceType.GetProperty(base.Description, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
}
}
See my table example in this question:
Localisation/I18n of database data in LINQ to SQL
The status type table maps to Enumeration values. The real benefit here is that you can have localisation in your reports and across your applications, and specify external IDs for integration with 3rd parties who don't want your internal values etc. It decouples the enum description from it's value.
You can't have multiple System.ComponentModel.DescriptionAttribute applied (so that option is out).
So add a level of indirection, the description holds a resource name, and then use the localisation support in resources. Clearly users of the enum will need to call your helper method to do this.
This looks good: http://www.codeproject.com/Articles/19980/Data-Binding-an-Enum-with-Descriptions