How to avoid using System.Reflection for displaying Enum attribute values in a ComboBox - c#

I am using an extension method to get the Name of a DisplayAttribute of an enum to load it into a combobox. This seems to be pretty processor intensive and the performance of the UI takes a hit.
What are some different ways to display a friendly name for an enum?
Extension method if you are interested:
public static string GetDisplayName<T>(this T enumValue) where T : IComparable, IFormattable, IConvertible
{
try
{
return enumValue.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>()
.GetName();
}
catch // If there's no DisplayAttribute.Name set, just return the ToString value
{
return enumValue.ToString();
}
}

Cache the values, basically.
For example, a static class EnumDisplayCache<T> could have a static constructor that populates a Dictionary<T, string> using your reflection approach and Enum.GetValues etc, with a:
public static bool GetDisplay(T value)
=> cache.TryGetValue(value, out name) ? name : value.ToString();
then your method becomes simply:
return EnumDisplayCache<T>.GetDisplay(enumValue);

You can try Enum.GetNames(typeof(YourEnum)) which return a string[] of all names in your enum.

You can use .Resx file, and you can use enum name as default displayname.
ResourceManager is static and hold key-values object. When you supply key as enum name and value as display name, you can get easly desired string value with enum name
// StringResources is my ResourceManager object which is generated during adding .Resx file in solution
string displayname = GetName(MyEnum.SomeType.ToString(), StringResources)
public string GetName(string key, ResourceManager resourceManager)
{
string displayName = resourceManager.GetString(key);
if (string.IsNullOrEmpty(displayName))
displayName = key;
return displayName;
}

Here is a full implementation of a way to setup an enum name lookup only once per enum per application run. Since it uses a static constructor, it will build the lookup map the first time you use if for a given enum type. This implementation keeps the extension method you originally had, but the implementation uses the cached name lookup.
// This class caches all value names for an enum the first time it is accessed
internal static class EnumNameCache<T> where T : struct, IComparable, IFormattable, IConvertible
{
private static Dictionary<T, string> sNameMap;
static EnumNameCache()
{
sNameMap = new Dictionary<T, string>();
Type type = typeof(T);
foreach (T value in Enum.GetValues(type).Cast<T>())
{
string valueName = value.ToString();
sNameMap.Add(value, type.GetMember(valueName)[0].GetCustomAttribute<DisplayAttribute>()?.Name ?? valueName);
}
}
public static string GetName(T value)
{
return sNameMap[value];
}
}
// Contains extension methods for enums
internal static class EnumExtensions
{
public static string GetDisplayName<T>(this T value) where T : struct, IComparable, IFormattable, IConvertible
{
return EnumNameCache<T>.GetName(value);
}
}
// Example display attribute with a Name property because System.ComponentModel.DisplayNameAttribute cannot be used on enum values
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
internal class DisplayAttribute : Attribute
{
public string Name { get; }
public DisplayAttribute(string name)
{
Name = name;
}
}
There will still be some reflection overhead when the name cache is first built for a given enum, but then lookups will be fast after that. Note that a null check is used on the attribute rather than a try/catch block because a null check is faster.

Related

how to parse an enum just based on a string? [duplicate]

What's the best way to convert a string to an enumeration value in C#?
I have an HTML select tag containing the values of an enumeration. When the page is posted, I want to pick up the value (which will be in the form of a string) and convert it to the enumeration value.
In an ideal world, I could do something like this:
StatusEnum MyStatus = StatusEnum.Parse("Active");
but that isn't a valid code.
In .NET Core and .NET >4 there is a generic parse method:
Enum.TryParse("Active", out StatusEnum myStatus);
This also includes C#7's new inline out variables, so this does the try-parse, conversion to the explicit enum type and initialises+populates the myStatus variable.
If you have access to C#7 and the latest .NET this is the best way.
Original Answer
In .NET it's rather ugly (until 4 or above):
StatusEnum MyStatus = (StatusEnum) Enum.Parse(typeof(StatusEnum), "Active", true);
I tend to simplify this with:
public static T ParseEnum<T>(string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}
Then I can do:
StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active");
One option suggested in the comments is to add an extension, which is simple enough:
public static T ToEnum<T>(this string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}
StatusEnum MyStatus = "Active".ToEnum<StatusEnum>();
Finally, you may want to have a default enum to use if the string cannot be parsed:
public static T ToEnum<T>(this string value, T defaultValue)
{
if (string.IsNullOrEmpty(value))
{
return defaultValue;
}
T result;
return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}
Which makes this the call:
StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);
However, I would be careful adding an extension method like this to string as (without namespace control) it will appear on all instances of string whether they hold an enum or not (so 1234.ToString().ToEnum(StatusEnum.None) would be valid but nonsensical) . It's often be best to avoid cluttering Microsoft's core classes with extra methods that only apply in very specific contexts unless your entire development team has a very good understanding of what those extensions do.
Use Enum.TryParse<T>(String, T) (≥ .NET 4.0):
StatusEnum myStatus;
Enum.TryParse("Active", out myStatus);
It can be simplified even further with C# 7.0's parameter type inlining:
Enum.TryParse("Active", out StatusEnum myStatus);
Note that the performance of Enum.Parse() is awful, because it is implemented via reflection. (The same is true of Enum.ToString, which goes the other way.)
If you need to convert strings to Enums in performance-sensitive code, your best bet is to create a Dictionary<String,YourEnum> at startup and use that to do your conversions.
You're looking for Enum.Parse.
SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
You can use extension methods now:
public static T ToEnum<T>(this string value, bool ignoreCase = true)
{
return (T) Enum.Parse(typeof (T), value, ignoreCase);
}
And you can call them by the below code (here, FilterType is an enum type):
FilterType filterType = type.ToEnum<FilterType>();
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);
So if you had an enum named mood it would look like this:
enum Mood
{
Angry,
Happy,
Sad
}
// ...
Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
Console.WriteLine("My mood is: {0}", m.ToString());
Enum.Parse is your friend:
StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
You can extend the accepted answer with a default value to avoid exceptions:
public static T ParseEnum<T>(string value, T defaultValue) where T : struct
{
try
{
T enumValue;
if (!Enum.TryParse(value, true, out enumValue))
{
return defaultValue;
}
return enumValue;
}
catch (Exception)
{
return defaultValue;
}
}
Then you call it like:
StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);
BEWARE:
enum Example
{
One = 1,
Two = 2,
Three = 3
}
Enum.(Try)Parse() accepts multiple, comma-separated arguments, and combines them with binary 'or' |. You cannot disable this and in my opinion you almost never want it.
var x = Enum.Parse("One,Two"); // x is now Three
Even if Three was not defined, x would still get int value 3. That's even worse: Enum.Parse() can give you a value that is not even defined for the enum!
I would not want to experience the consequences of users, willingly or unwillingly, triggering this behavior.
Additionally, as mentioned by others, performance is less than ideal for large enums, namely linear in the number of possible values.
I suggest the following:
public static bool TryParse<T>(string value, out T result)
where T : struct
{
var cacheKey = "Enum_" + typeof(T).FullName;
// [Use MemoryCache to retrieve or create&store a dictionary for this enum, permanently or temporarily.
// [Implementation off-topic.]
var enumDictionary = CacheHelper.GetCacheItem(cacheKey, CreateEnumDictionary<T>, EnumCacheExpiration);
return enumDictionary.TryGetValue(value.Trim(), out result);
}
private static Dictionary<string, T> CreateEnumDictionary<T>()
{
return Enum.GetValues(typeof(T))
.Cast<T>()
.ToDictionary(value => value.ToString(), value => value, StringComparer.OrdinalIgnoreCase);
}
We couldn't assume perfectly valid input, and went with this variation of #Keith's answer:
public static TEnum ParseEnum<TEnum>(string value) where TEnum : struct
{
TEnum tmp;
if (!Enum.TryParse<TEnum>(value, true, out tmp))
{
tmp = new TEnum();
}
return tmp;
}
// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str)
{
return (T) Enum.Parse(typeof(T), str);
}
Parses string to TEnum without try/catch and without TryParse() method from .NET 4.5
/// <summary>
/// Parses string to TEnum without try/catch and .NET 4.5 TryParse()
/// </summary>
public static bool TryParseToEnum<TEnum>(string probablyEnumAsString_, out TEnum enumValue_) where TEnum : struct
{
enumValue_ = (TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0);
if(!Enum.IsDefined(typeof(TEnum), probablyEnumAsString_))
return false;
enumValue_ = (TEnum) Enum.Parse(typeof(TEnum), probablyEnumAsString_);
return true;
}
Super simple code using TryParse:
var value = "Active";
StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
status = StatusEnum.Unknown;
I like the extension method solution..
namespace System
{
public static class StringExtensions
{
public static bool TryParseAsEnum<T>(this string value, out T output) where T : struct
{
T result;
var isEnum = Enum.TryParse(value, out result);
output = isEnum ? result : default(T);
return isEnum;
}
}
}
Here below my implementation with tests.
using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
using static System.Console;
private enum Countries
{
NorthAmerica,
Europe,
Rusia,
Brasil,
China,
Asia,
Australia
}
[TestMethod]
public void StringExtensions_On_TryParseAsEnum()
{
var countryName = "Rusia";
Countries country;
var isCountry = countryName.TryParseAsEnum(out country);
WriteLine(country);
IsTrue(isCountry);
AreEqual(Countries.Rusia, country);
countryName = "Don't exist";
isCountry = countryName.TryParseAsEnum(out country);
WriteLine(country);
IsFalse(isCountry);
AreEqual(Countries.NorthAmerica, country); // the 1rst one in the enumeration
}
public static T ParseEnum<T>(string value) //function declaration
{
return (T) Enum.Parse(typeof(T), value);
}
Importance imp = EnumUtil.ParseEnum<Importance>("Active"); //function call
====================A Complete Program====================
using System;
class Program
{
enum PetType
{
None,
Cat = 1,
Dog = 2
}
static void Main()
{
// Possible user input:
string value = "Dog";
// Try to convert the string to an enum:
PetType pet = (PetType)Enum.Parse(typeof(PetType), value);
// See if the conversion succeeded:
if (pet == PetType.Dog)
{
Console.WriteLine("Equals dog.");
}
}
}
-------------
Output
Equals dog.
I used class (strongly-typed version of Enum with parsing and performance improvements). I found it on GitHub, and it should work for .NET 3.5 too. It has some memory overhead since it buffers a dictionary.
StatusEnum MyStatus = Enum<StatusEnum>.Parse("Active");
The blogpost is Enums – Better syntax, improved performance and TryParse in NET 3.5.
And code:
https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs
For performance this might help:
private static Dictionary<Type, Dictionary<string, object>> dicEnum = new Dictionary<Type, Dictionary<string, object>>();
public static T ToEnum<T>(this string value, T defaultValue)
{
var t = typeof(T);
Dictionary<string, object> dic;
if (!dicEnum.ContainsKey(t))
{
dic = new Dictionary<string, object>();
dicEnum.Add(t, dic);
foreach (var en in Enum.GetValues(t))
dic.Add(en.ToString(), en);
}
else
dic = dicEnum[t];
if (!dic.ContainsKey(value))
return defaultValue;
else
return (T)dic[value];
}
I found that here the case with enum values that have EnumMember value was not considered. So here we go:
using System.Runtime.Serialization;
public static TEnum ToEnum<TEnum>(this string value, TEnum defaultValue) where TEnum : struct
{
if (string.IsNullOrEmpty(value))
{
return defaultValue;
}
TEnum result;
var enumType = typeof(TEnum);
foreach (var enumName in Enum.GetNames(enumType))
{
var fieldInfo = enumType.GetField(enumName);
var enumMemberAttribute = ((EnumMemberAttribute[]) fieldInfo.GetCustomAttributes(typeof(EnumMemberAttribute), true)).FirstOrDefault();
if (enumMemberAttribute?.Value == value)
{
return Enum.TryParse(enumName, true, out result) ? result : defaultValue;
}
}
return Enum.TryParse(value, true, out result) ? result : defaultValue;
}
And example of that enum:
public enum OracleInstanceStatus
{
Unknown = -1,
Started = 1,
Mounted = 2,
Open = 3,
[EnumMember(Value = "OPEN MIGRATE")]
OpenMigrate = 4
}
You have to use Enum.Parse to get the object value from Enum, after that you have to change the object value to specific enum value. Casting to enum value can be do by using Convert.ChangeType. Please have a look on following code snippet
public T ConvertStringValueToEnum<T>(string valueToParse){
return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
}

How do I efficiently parse a string in C# to return a similarly-named enum? [duplicate]

What's the best way to convert a string to an enumeration value in C#?
I have an HTML select tag containing the values of an enumeration. When the page is posted, I want to pick up the value (which will be in the form of a string) and convert it to the enumeration value.
In an ideal world, I could do something like this:
StatusEnum MyStatus = StatusEnum.Parse("Active");
but that isn't a valid code.
In .NET Core and .NET >4 there is a generic parse method:
Enum.TryParse("Active", out StatusEnum myStatus);
This also includes C#7's new inline out variables, so this does the try-parse, conversion to the explicit enum type and initialises+populates the myStatus variable.
If you have access to C#7 and the latest .NET this is the best way.
Original Answer
In .NET it's rather ugly (until 4 or above):
StatusEnum MyStatus = (StatusEnum) Enum.Parse(typeof(StatusEnum), "Active", true);
I tend to simplify this with:
public static T ParseEnum<T>(string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}
Then I can do:
StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active");
One option suggested in the comments is to add an extension, which is simple enough:
public static T ToEnum<T>(this string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}
StatusEnum MyStatus = "Active".ToEnum<StatusEnum>();
Finally, you may want to have a default enum to use if the string cannot be parsed:
public static T ToEnum<T>(this string value, T defaultValue)
{
if (string.IsNullOrEmpty(value))
{
return defaultValue;
}
T result;
return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}
Which makes this the call:
StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);
However, I would be careful adding an extension method like this to string as (without namespace control) it will appear on all instances of string whether they hold an enum or not (so 1234.ToString().ToEnum(StatusEnum.None) would be valid but nonsensical) . It's often be best to avoid cluttering Microsoft's core classes with extra methods that only apply in very specific contexts unless your entire development team has a very good understanding of what those extensions do.
Use Enum.TryParse<T>(String, T) (≥ .NET 4.0):
StatusEnum myStatus;
Enum.TryParse("Active", out myStatus);
It can be simplified even further with C# 7.0's parameter type inlining:
Enum.TryParse("Active", out StatusEnum myStatus);
Note that the performance of Enum.Parse() is awful, because it is implemented via reflection. (The same is true of Enum.ToString, which goes the other way.)
If you need to convert strings to Enums in performance-sensitive code, your best bet is to create a Dictionary<String,YourEnum> at startup and use that to do your conversions.
You're looking for Enum.Parse.
SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
You can use extension methods now:
public static T ToEnum<T>(this string value, bool ignoreCase = true)
{
return (T) Enum.Parse(typeof (T), value, ignoreCase);
}
And you can call them by the below code (here, FilterType is an enum type):
FilterType filterType = type.ToEnum<FilterType>();
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);
So if you had an enum named mood it would look like this:
enum Mood
{
Angry,
Happy,
Sad
}
// ...
Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
Console.WriteLine("My mood is: {0}", m.ToString());
Enum.Parse is your friend:
StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
You can extend the accepted answer with a default value to avoid exceptions:
public static T ParseEnum<T>(string value, T defaultValue) where T : struct
{
try
{
T enumValue;
if (!Enum.TryParse(value, true, out enumValue))
{
return defaultValue;
}
return enumValue;
}
catch (Exception)
{
return defaultValue;
}
}
Then you call it like:
StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);
BEWARE:
enum Example
{
One = 1,
Two = 2,
Three = 3
}
Enum.(Try)Parse() accepts multiple, comma-separated arguments, and combines them with binary 'or' |. You cannot disable this and in my opinion you almost never want it.
var x = Enum.Parse("One,Two"); // x is now Three
Even if Three was not defined, x would still get int value 3. That's even worse: Enum.Parse() can give you a value that is not even defined for the enum!
I would not want to experience the consequences of users, willingly or unwillingly, triggering this behavior.
Additionally, as mentioned by others, performance is less than ideal for large enums, namely linear in the number of possible values.
I suggest the following:
public static bool TryParse<T>(string value, out T result)
where T : struct
{
var cacheKey = "Enum_" + typeof(T).FullName;
// [Use MemoryCache to retrieve or create&store a dictionary for this enum, permanently or temporarily.
// [Implementation off-topic.]
var enumDictionary = CacheHelper.GetCacheItem(cacheKey, CreateEnumDictionary<T>, EnumCacheExpiration);
return enumDictionary.TryGetValue(value.Trim(), out result);
}
private static Dictionary<string, T> CreateEnumDictionary<T>()
{
return Enum.GetValues(typeof(T))
.Cast<T>()
.ToDictionary(value => value.ToString(), value => value, StringComparer.OrdinalIgnoreCase);
}
We couldn't assume perfectly valid input, and went with this variation of #Keith's answer:
public static TEnum ParseEnum<TEnum>(string value) where TEnum : struct
{
TEnum tmp;
if (!Enum.TryParse<TEnum>(value, true, out tmp))
{
tmp = new TEnum();
}
return tmp;
}
// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str)
{
return (T) Enum.Parse(typeof(T), str);
}
Parses string to TEnum without try/catch and without TryParse() method from .NET 4.5
/// <summary>
/// Parses string to TEnum without try/catch and .NET 4.5 TryParse()
/// </summary>
public static bool TryParseToEnum<TEnum>(string probablyEnumAsString_, out TEnum enumValue_) where TEnum : struct
{
enumValue_ = (TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0);
if(!Enum.IsDefined(typeof(TEnum), probablyEnumAsString_))
return false;
enumValue_ = (TEnum) Enum.Parse(typeof(TEnum), probablyEnumAsString_);
return true;
}
Super simple code using TryParse:
var value = "Active";
StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
status = StatusEnum.Unknown;
I like the extension method solution..
namespace System
{
public static class StringExtensions
{
public static bool TryParseAsEnum<T>(this string value, out T output) where T : struct
{
T result;
var isEnum = Enum.TryParse(value, out result);
output = isEnum ? result : default(T);
return isEnum;
}
}
}
Here below my implementation with tests.
using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
using static System.Console;
private enum Countries
{
NorthAmerica,
Europe,
Rusia,
Brasil,
China,
Asia,
Australia
}
[TestMethod]
public void StringExtensions_On_TryParseAsEnum()
{
var countryName = "Rusia";
Countries country;
var isCountry = countryName.TryParseAsEnum(out country);
WriteLine(country);
IsTrue(isCountry);
AreEqual(Countries.Rusia, country);
countryName = "Don't exist";
isCountry = countryName.TryParseAsEnum(out country);
WriteLine(country);
IsFalse(isCountry);
AreEqual(Countries.NorthAmerica, country); // the 1rst one in the enumeration
}
public static T ParseEnum<T>(string value) //function declaration
{
return (T) Enum.Parse(typeof(T), value);
}
Importance imp = EnumUtil.ParseEnum<Importance>("Active"); //function call
====================A Complete Program====================
using System;
class Program
{
enum PetType
{
None,
Cat = 1,
Dog = 2
}
static void Main()
{
// Possible user input:
string value = "Dog";
// Try to convert the string to an enum:
PetType pet = (PetType)Enum.Parse(typeof(PetType), value);
// See if the conversion succeeded:
if (pet == PetType.Dog)
{
Console.WriteLine("Equals dog.");
}
}
}
-------------
Output
Equals dog.
I used class (strongly-typed version of Enum with parsing and performance improvements). I found it on GitHub, and it should work for .NET 3.5 too. It has some memory overhead since it buffers a dictionary.
StatusEnum MyStatus = Enum<StatusEnum>.Parse("Active");
The blogpost is Enums – Better syntax, improved performance and TryParse in NET 3.5.
And code:
https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs
For performance this might help:
private static Dictionary<Type, Dictionary<string, object>> dicEnum = new Dictionary<Type, Dictionary<string, object>>();
public static T ToEnum<T>(this string value, T defaultValue)
{
var t = typeof(T);
Dictionary<string, object> dic;
if (!dicEnum.ContainsKey(t))
{
dic = new Dictionary<string, object>();
dicEnum.Add(t, dic);
foreach (var en in Enum.GetValues(t))
dic.Add(en.ToString(), en);
}
else
dic = dicEnum[t];
if (!dic.ContainsKey(value))
return defaultValue;
else
return (T)dic[value];
}
I found that here the case with enum values that have EnumMember value was not considered. So here we go:
using System.Runtime.Serialization;
public static TEnum ToEnum<TEnum>(this string value, TEnum defaultValue) where TEnum : struct
{
if (string.IsNullOrEmpty(value))
{
return defaultValue;
}
TEnum result;
var enumType = typeof(TEnum);
foreach (var enumName in Enum.GetNames(enumType))
{
var fieldInfo = enumType.GetField(enumName);
var enumMemberAttribute = ((EnumMemberAttribute[]) fieldInfo.GetCustomAttributes(typeof(EnumMemberAttribute), true)).FirstOrDefault();
if (enumMemberAttribute?.Value == value)
{
return Enum.TryParse(enumName, true, out result) ? result : defaultValue;
}
}
return Enum.TryParse(value, true, out result) ? result : defaultValue;
}
And example of that enum:
public enum OracleInstanceStatus
{
Unknown = -1,
Started = 1,
Mounted = 2,
Open = 3,
[EnumMember(Value = "OPEN MIGRATE")]
OpenMigrate = 4
}
You have to use Enum.Parse to get the object value from Enum, after that you have to change the object value to specific enum value. Casting to enum value can be do by using Convert.ChangeType. Please have a look on following code snippet
public T ConvertStringValueToEnum<T>(string valueToParse){
return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
}

Handling interactions between generic and static types

I am writing a generic method where I would like a different execution path to occur based on the type of the generic Type parameter. The different execution paths are statically typed, e.g.
public static T Get<T>(this NameValueCollection collection, string name) where T : struct
{
//Perform test on type, if it matches, delegate to statically typed method.
if (typeof(T) == typeof(int)) return (T)(object)GetInt32(collection, name);
else if (typeof(T) == typeof(DateTime)) return (T) (object) GetDateTime(collection, name);
//Other types parsed here...
//If nothing matched, return default.
return default(T);
}
The only way I've found to be able to use the return result of the static execution path is to box it as an object, and then cast it to 'T'.
To me this defeats the purpose of using a generic method in the first place (other than gaining some syntactical sugar). Does anyone know a way of being able to return the int value as T, in cases where we have already established that T is of type int?
I was looking at using a var of type 'dynamic' but read that it just end sup using object behind the scenes anyway.
Is this, perhaps, the extent of generics?
--
Updated to include my final approach, based on smartcaveman's reply, which uses the type resolution of generic static classes to determine which 'parsing' method to use, without boxing or using dynamic.
public class StringParser
{
private class Getter<T>
{
private static readonly ConcurrentDictionary<StringParser, Getter<T>> Getters = new ConcurrentDictionary<StringParser, Getter<T>>();
public Func<string, T> Get { get; set; }
private Getter() {}
public static Getter<T> For(StringParser stringParser)
{
return Getters.GetOrAdd(stringParser, x => new Getter<T>());
}
}
public virtual T Get<T>(string value)
{
var get = Getter<T>.For(this).Get;
if (get == null) throw new InvalidOperationException(string.Format("No 'get' has been configured for values of type '{0}'.", typeof (T).Name));
return get(value);
}
public void SetupGet<T>(Func<string, T> get)
{
Getter<T>.For(this).Get = get;
}
}
Fairly simple to use:
public static void Usage()
{
StringParser parser = new StringParser();
parser.SetupGet(Int32.Parse);
int myInt = parser.Get<int>("3");
}
The trick of smartcaveman's method is that generic static classes with different type parameters are actually considered different Types, and do not share static members.
Very cool stuff, thank you!
Unless you can use a strongly typed keyed collection (e.g. Dictionary<string,int>), you're going to have to box the value. There is not a work around.
That being said, it is not clear how your method is anymore useful than a non-generic version. I'm not seeing the calling code, but it seems like the only relevant case is the int, since every other case just returns the default value.
Also, you're correct about dynamic.
Update
The idea of using a dictionary would apply if there were not multiple possible types of value. However, if there were only 1 possible type of value (e.g. int) then you could use a Dictionary<string,int> instead of a NameValueCollection.
I wrote a small sample that might give you ideas as to how you could keep strong typing with a custom class. I have omitted null-checking and argument validation logic, and this has neither been tested nor compiled. However, the basic idea should be clear. You could use the ValueRegistry class with your NameValueCollection as follows.
// around application start, configure the way values are retrieved
// from names for different types. Note that this doesn't need to use
// a NameValueCollection, but I did so to stay consistent.
var collection = new NameValueCollection();
ValueRegistry.Configure<int>(name => GetInt32(collection,name));
ValueRegistry.Configure<DateTime>(name => GetDateTime(collection,name));
// where you are going to need to get values
var values = new ValueRegistry();
int value = values.Get<int>("the name"); // nothing is boxed
public class ValueRegistry
{
private class Provider<T>
where T : struct
{
private static readonly ConcurrentDictionary<ValueRegistry,Provider<T>> Providers = new ConcurrentDictionary<ValueRegistry,Provider<T>>();
public static Provider<T> For(ValueRegistry registry)
{
return Providers.GetOrAdd(registry, x => new Provider<T>());
}
private Provider(){
this.entries = new Dictionary<string,T>();
}
private readonly Dictionary<string,T> entries;
private static Func<string,T> CustomGetter;
public static void Configure(Func<string,T> getter) { CustomGetter = getter;}
public static T GetValueOrDefault(string name)
{
T value;
if(!entries.TryGetValue(name, out value))
entries[name] = value = CustomGetter != null ? CustomGetter(name) : default(T);
return value;
}
}
public T Get<T>(string name)
where T : struct
{
return Provider<T>.For(this).GetValueOrDefault(name);
}
public static void Configure<T>(Func<string,T> customGetter)
where T : struct
{
Provider<T>.Configure(customGetter);
}
}
That kind of dispatch is possible using dynamic features introduced in C# 4.0 (and next versions support it too).
This code does what you've expressed here:
public static T Get<T>(this NameValueCollection collection, string name) where T : struct
{
T v = default(T);
dynamic indicator = v;
return GetValue(collection, name, indicator);
}
static int GetValue(NameValueCollection collection, string name, int indicator)
{
return 110;
}
static DateTime GetValue(NameValueCollection collection, string name, DateTime indicator)
{
return DateTime.Now;
}
// ... other helper parsers
// if nothing else matched
static object GetValue(NameValueCollection collection, string name, object indicator)
{
return indicator;
}
To perform a smoke test:
Console.WriteLine(Get<int>(null, null));
Console.WriteLine(Get<DateTime>(null, null));
Console.WriteLine(Get<double>(null, null));
Yes you have to box (cast value type to object) explicitly before casting it to generic T even you have stated where T : struct. You can do something like below but I can not say it is more elegant.
return (T) Convert.ChangeType(GetInt32(collection, name), typeof (int));
You could use a Dictionary to handle this.
private static Dictionary<Type, Func<NameValueCollection, string, T>> _typeMap = new Dictionary<Type, Func<NameValueCollection, string, T>>();
static Constructor()
{
_typeMap[typeof(DateTime)] = (nvc, name) => { return (T)GetDateTime(nvc, name); };
// etc
}
public static T Get<T>(this NameValueCollection collection, string name) where T : struct
{
return _typeMap[typeof(T)](collection, name);
}

Casting a String to a Type in Unity C# [duplicate]

What's the best way to convert a string to an enumeration value in C#?
I have an HTML select tag containing the values of an enumeration. When the page is posted, I want to pick up the value (which will be in the form of a string) and convert it to the enumeration value.
In an ideal world, I could do something like this:
StatusEnum MyStatus = StatusEnum.Parse("Active");
but that isn't a valid code.
In .NET Core and .NET >4 there is a generic parse method:
Enum.TryParse("Active", out StatusEnum myStatus);
This also includes C#7's new inline out variables, so this does the try-parse, conversion to the explicit enum type and initialises+populates the myStatus variable.
If you have access to C#7 and the latest .NET this is the best way.
Original Answer
In .NET it's rather ugly (until 4 or above):
StatusEnum MyStatus = (StatusEnum) Enum.Parse(typeof(StatusEnum), "Active", true);
I tend to simplify this with:
public static T ParseEnum<T>(string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}
Then I can do:
StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active");
One option suggested in the comments is to add an extension, which is simple enough:
public static T ToEnum<T>(this string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}
StatusEnum MyStatus = "Active".ToEnum<StatusEnum>();
Finally, you may want to have a default enum to use if the string cannot be parsed:
public static T ToEnum<T>(this string value, T defaultValue)
{
if (string.IsNullOrEmpty(value))
{
return defaultValue;
}
T result;
return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}
Which makes this the call:
StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);
However, I would be careful adding an extension method like this to string as (without namespace control) it will appear on all instances of string whether they hold an enum or not (so 1234.ToString().ToEnum(StatusEnum.None) would be valid but nonsensical) . It's often be best to avoid cluttering Microsoft's core classes with extra methods that only apply in very specific contexts unless your entire development team has a very good understanding of what those extensions do.
Use Enum.TryParse<T>(String, T) (≥ .NET 4.0):
StatusEnum myStatus;
Enum.TryParse("Active", out myStatus);
It can be simplified even further with C# 7.0's parameter type inlining:
Enum.TryParse("Active", out StatusEnum myStatus);
Note that the performance of Enum.Parse() is awful, because it is implemented via reflection. (The same is true of Enum.ToString, which goes the other way.)
If you need to convert strings to Enums in performance-sensitive code, your best bet is to create a Dictionary<String,YourEnum> at startup and use that to do your conversions.
You're looking for Enum.Parse.
SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
You can use extension methods now:
public static T ToEnum<T>(this string value, bool ignoreCase = true)
{
return (T) Enum.Parse(typeof (T), value, ignoreCase);
}
And you can call them by the below code (here, FilterType is an enum type):
FilterType filterType = type.ToEnum<FilterType>();
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);
So if you had an enum named mood it would look like this:
enum Mood
{
Angry,
Happy,
Sad
}
// ...
Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
Console.WriteLine("My mood is: {0}", m.ToString());
Enum.Parse is your friend:
StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
You can extend the accepted answer with a default value to avoid exceptions:
public static T ParseEnum<T>(string value, T defaultValue) where T : struct
{
try
{
T enumValue;
if (!Enum.TryParse(value, true, out enumValue))
{
return defaultValue;
}
return enumValue;
}
catch (Exception)
{
return defaultValue;
}
}
Then you call it like:
StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);
BEWARE:
enum Example
{
One = 1,
Two = 2,
Three = 3
}
Enum.(Try)Parse() accepts multiple, comma-separated arguments, and combines them with binary 'or' |. You cannot disable this and in my opinion you almost never want it.
var x = Enum.Parse("One,Two"); // x is now Three
Even if Three was not defined, x would still get int value 3. That's even worse: Enum.Parse() can give you a value that is not even defined for the enum!
I would not want to experience the consequences of users, willingly or unwillingly, triggering this behavior.
Additionally, as mentioned by others, performance is less than ideal for large enums, namely linear in the number of possible values.
I suggest the following:
public static bool TryParse<T>(string value, out T result)
where T : struct
{
var cacheKey = "Enum_" + typeof(T).FullName;
// [Use MemoryCache to retrieve or create&store a dictionary for this enum, permanently or temporarily.
// [Implementation off-topic.]
var enumDictionary = CacheHelper.GetCacheItem(cacheKey, CreateEnumDictionary<T>, EnumCacheExpiration);
return enumDictionary.TryGetValue(value.Trim(), out result);
}
private static Dictionary<string, T> CreateEnumDictionary<T>()
{
return Enum.GetValues(typeof(T))
.Cast<T>()
.ToDictionary(value => value.ToString(), value => value, StringComparer.OrdinalIgnoreCase);
}
We couldn't assume perfectly valid input, and went with this variation of #Keith's answer:
public static TEnum ParseEnum<TEnum>(string value) where TEnum : struct
{
TEnum tmp;
if (!Enum.TryParse<TEnum>(value, true, out tmp))
{
tmp = new TEnum();
}
return tmp;
}
// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str)
{
return (T) Enum.Parse(typeof(T), str);
}
Parses string to TEnum without try/catch and without TryParse() method from .NET 4.5
/// <summary>
/// Parses string to TEnum without try/catch and .NET 4.5 TryParse()
/// </summary>
public static bool TryParseToEnum<TEnum>(string probablyEnumAsString_, out TEnum enumValue_) where TEnum : struct
{
enumValue_ = (TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0);
if(!Enum.IsDefined(typeof(TEnum), probablyEnumAsString_))
return false;
enumValue_ = (TEnum) Enum.Parse(typeof(TEnum), probablyEnumAsString_);
return true;
}
Super simple code using TryParse:
var value = "Active";
StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
status = StatusEnum.Unknown;
I like the extension method solution..
namespace System
{
public static class StringExtensions
{
public static bool TryParseAsEnum<T>(this string value, out T output) where T : struct
{
T result;
var isEnum = Enum.TryParse(value, out result);
output = isEnum ? result : default(T);
return isEnum;
}
}
}
Here below my implementation with tests.
using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
using static System.Console;
private enum Countries
{
NorthAmerica,
Europe,
Rusia,
Brasil,
China,
Asia,
Australia
}
[TestMethod]
public void StringExtensions_On_TryParseAsEnum()
{
var countryName = "Rusia";
Countries country;
var isCountry = countryName.TryParseAsEnum(out country);
WriteLine(country);
IsTrue(isCountry);
AreEqual(Countries.Rusia, country);
countryName = "Don't exist";
isCountry = countryName.TryParseAsEnum(out country);
WriteLine(country);
IsFalse(isCountry);
AreEqual(Countries.NorthAmerica, country); // the 1rst one in the enumeration
}
public static T ParseEnum<T>(string value) //function declaration
{
return (T) Enum.Parse(typeof(T), value);
}
Importance imp = EnumUtil.ParseEnum<Importance>("Active"); //function call
====================A Complete Program====================
using System;
class Program
{
enum PetType
{
None,
Cat = 1,
Dog = 2
}
static void Main()
{
// Possible user input:
string value = "Dog";
// Try to convert the string to an enum:
PetType pet = (PetType)Enum.Parse(typeof(PetType), value);
// See if the conversion succeeded:
if (pet == PetType.Dog)
{
Console.WriteLine("Equals dog.");
}
}
}
-------------
Output
Equals dog.
I used class (strongly-typed version of Enum with parsing and performance improvements). I found it on GitHub, and it should work for .NET 3.5 too. It has some memory overhead since it buffers a dictionary.
StatusEnum MyStatus = Enum<StatusEnum>.Parse("Active");
The blogpost is Enums – Better syntax, improved performance and TryParse in NET 3.5.
And code:
https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs
For performance this might help:
private static Dictionary<Type, Dictionary<string, object>> dicEnum = new Dictionary<Type, Dictionary<string, object>>();
public static T ToEnum<T>(this string value, T defaultValue)
{
var t = typeof(T);
Dictionary<string, object> dic;
if (!dicEnum.ContainsKey(t))
{
dic = new Dictionary<string, object>();
dicEnum.Add(t, dic);
foreach (var en in Enum.GetValues(t))
dic.Add(en.ToString(), en);
}
else
dic = dicEnum[t];
if (!dic.ContainsKey(value))
return defaultValue;
else
return (T)dic[value];
}
I found that here the case with enum values that have EnumMember value was not considered. So here we go:
using System.Runtime.Serialization;
public static TEnum ToEnum<TEnum>(this string value, TEnum defaultValue) where TEnum : struct
{
if (string.IsNullOrEmpty(value))
{
return defaultValue;
}
TEnum result;
var enumType = typeof(TEnum);
foreach (var enumName in Enum.GetNames(enumType))
{
var fieldInfo = enumType.GetField(enumName);
var enumMemberAttribute = ((EnumMemberAttribute[]) fieldInfo.GetCustomAttributes(typeof(EnumMemberAttribute), true)).FirstOrDefault();
if (enumMemberAttribute?.Value == value)
{
return Enum.TryParse(enumName, true, out result) ? result : defaultValue;
}
}
return Enum.TryParse(value, true, out result) ? result : defaultValue;
}
And example of that enum:
public enum OracleInstanceStatus
{
Unknown = -1,
Started = 1,
Mounted = 2,
Open = 3,
[EnumMember(Value = "OPEN MIGRATE")]
OpenMigrate = 4
}
You have to use Enum.Parse to get the object value from Enum, after that you have to change the object value to specific enum value. Casting to enum value can be do by using Convert.ChangeType. Please have a look on following code snippet
public T ConvertStringValueToEnum<T>(string valueToParse){
return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
}

Enum Extension Method is not showing

I'm trying to add new/extension method for Enum but the extension method is not showing on intellisense method list. Please help here's my code.
Extension:
public static class EnumExtensions
{
public static string GetDescriptionAttr(this Enum value,string key)
{
var type = value.GetType();
var memInfo = type.GetMember(key);
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute),
false);
var description = ((DescriptionAttribute)attributes[0]).Description;
return description;
}
}
Trying to call the result from other class (both caller and extension are in the same project)
Extension methods can be applied on instances only
public static class EnumExtensions {
// This extension method requires "value" argument
// that should be an instance of Enum class
public static string GetDescriptionAttr(this Enum value, string key) {
...
}
}
...
public enum MyEnum {
One,
Two,
Three
}
Enum myEnum = MyEnum.One;
// You can call extension method on instance (myEnum) only
myEnum.GetDescriptionAttr("One");
You should use extension method for an instance of your enum.
I have this code and it works properly:
public static string GetDescription(this Enum value)
{
var attributes =
(DescriptionAttribute[])value.GetType().GetField(value.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}
And using of this method shows here:
MyEnum myE = MyEnum.OneOfItemsOfEnum;
string description = myE.GetDescription();

Resources