Generic Method Enum To String Conversion - c#

I have seen lots of method to convert a string to an enum using generics but cannot find a neat way to convert an enum to string using generics.
What I mean is Pass an enum and a value and return the mapped name of the enum.
Any suggestions

How about:
enum E
{
A = 2,
B = 3
}
public static string GetLiteral<T>(object value)
{
return Enum.GetName(typeof(T), value);
}
static void Main(string[] args)
{
Console.WriteLine(GetLiteral<E>(2));
Console.WriteLine(GetLiteral<E>(3));
}

This works when you know the value, and type of the enum but you want to get the enum instance back that is matching value..
static T ConvertToEnum<T>(object value)
{
return (T) Enum.Parse(typeof(T), Enum.GetName(typeof(T), value));
}
static void Main(string[] args)
{
Gender g1 = ConvertToEnum<Gender>(0); //Male
Gender g2 = ConvertToEnum<Gender>(1); //Female
Gender g3 = ConvertToEnum<Gender>(2); //*BANG* exception
}

I would write a extension method to do so eg
using System.ComponentModel;
public enum StatusResult
{
[Description("Success")]
Success,
[Description("Failure...")]
Failure
}
public static class AttributesHelperExtension
{
public static string ToDescription(this Enum value)
{
DescriptionAttribute[] da = (DescriptionAttribute[])(value.GetType().GetField(value.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false);
return da.Length > 0 ? da[0].Description : value.ToString();
}
public static T ToEnum<T>(this string stringValue, T defaultValue)
{
foreach (T enumValue in Enum.GetValues(typeof(T)))
{
DescriptionAttribute[] da = (DescriptionAttribute[])(typeof(T).GetField(enumValue.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false);
if (da.Length > 0 && da[0].Description == stringValue)
return enumValue;
}
return defaultValue;
}
}
Now to call this use
string value = StatusResult.Failure.ToDescription();

I came across this method that I used to use a while ago.
It uses the Extensions, and should always return an enum
public static T ToEnum<T>(this string type, T defaultEnum)
{
T holder;
try
{
holder = (T)Enum.Parse(typeof(T), type);
}
catch
{
holder = defaultEnum;
}
return holder;
}

Related

How to use Generic interface with two type in return of method

I need to create an interface with 2 type and use it as a method return value.
public interface StringLong<T1,T2>
where T1 : string
where T2 : long
{}
StringLong<T1,T2> method StringLong<T1,T2>()
It makes no sense to define an interface with two generic types that you constrain to just string and long.
It sounds like you just want a tuple:
(string, long) MyMethod()
{
return ("Hello", 42L);
}
You can even name the return values:
(string message, long meaningOfLife) MyMethod()
{
return ("Hello", 42L);
}
Then you can write:
var result = MyMethod();
Console.WriteLine(result.message);
Console.WriteLine(result.meaningOfLife);
I think is the functionality you are trying to achieve (from the comments). Since the return might be of either string or long there common ancestor is object.
Once you have the value you can use pattern matching to cast the result into the appropriate type:
static class Program
{
static void Main(string[] args)
{
var obj = MethodReturnsStringOrLong(1722);
switch (obj)
{
case string str:
Console.WriteLine($"String is {str}");
break;
case long lng:
Console.WriteLine($"Long is {lng}");
break;
default:
throw new NotSupportedException();
}
}
public static object MethodReturnsStringOrLong(int input)
{
if (input % 2 == 0)
{
return 1928374028203384L;
}
else
{
return "ASIDJMFHSOASKSJHD";
}
}
}
An alternative is the create your own common ancestor, like the class Value below that might contains either a long and/or a string.
public class Value
{
public Value(long longValue)
{
LongValue = longValue;
}
public Value(string stringValue)
{
StringValue = stringValue;
}
public long? LongValue { get; }
public string StringValue { get; }
}
static class Program
{
static void Main(string[] args)
{
var obj = MethodReturnsStringOrLong(1722);
if (obj.LongValue.HasValue)
{
Console.WriteLine($"Long is {obj.LongValue.Value}");
}
if (!string.IsNullOrEmpty(obj.StringValue))
{
Console.WriteLine($"String is {obj.StringValue}");
}
}
public static Value MethodReturnsStringOrLong(int input)
{
if (input % 2 == 0)
{
return new Value(1928374028203384L);
}
else
{
return new Value("ASIDJMFHSOASKSJHD");
}
}
}

c# Generics for Attribute helper methods

I cannot find a good way to make this DRY in .Net Core. (Dont repeat yourself). How can I make it so I'm not repeating majority of the logic? Here are the 2 methods:
public static string GetCategory(this Enum val)
{
CategoryAttribute[] attributes = (CategoryAttribute[])val
.GetType()
.GetField(val.ToString())
.GetCustomAttributes(typeof(CategoryAttribute), false);
return attributes.Length > 0 ? attributes[0].Category : string.Empty;
}
public static string GetDescription(this Enum val)
{
DescriptionAttribute[] attributes = (DescriptionAttribute[])val
.GetType()
.GetField(val.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : string.Empty;
}
I'd start with this:
public static T GetAttribute<T>(this Enum val)
where T : Attribute
{
return (T)val
.GetType()
.GetField(val.ToString())
.GetCustomAttribute(typeof(T), false);
}
Which turns your methods into this:
public static string GetCategory(this Enum val)
{
return val.GetAttribute<CategoryAttribute>()?.Category ?? string.Empty;
}
public static string GetDescription(this Enum val)
{
return val.GetAttribute<DescriptionAttribute>()?.Description ?? string.Empty;
}
You could arguably do more to make those final methods a little more DRY, but I'm guessing the pattern that you're using here (getting a property from an attribute and returning its value or an empty string) probably isn't common enough to be worth creating a method specifically for that. The GetAttribute method, on the other hand, is likely to be a lot more reusable.
You can use the generic version of GetCustomAttribute<T> instead which simplifies the code enough to where another abstraction is not necessary IMO.
public static string GetCategory(this Enum val)
{
return val.GetType()
.GetField(val.ToString())
.GetCustomAttribute<CategoryAttribute>(false)?.Category ?? string.Empty;
}
public static string GetDescription(this Enum val)
{
return val.GetType()
.GetField(val.ToString())
.GetCustomAttribute<DescriptionAttribute>(false)?.Description ?? string.Empty;
}
In C# 7.3, you can constraint your methods to enum types.
This will save you one boxing of your enum.
public static class AttributeExtensions
{
public static string GetCategory<T>(this T val) where T: Enum
{
return GetAttr<CategoryAttribute, T>(val)?.Category ?? "";
}
public static string GetDescription<T>(this T val) where T : Enum
{
return GetAttr<DescriptionAttribute, T>(val)?.Description ?? "";
}
private static TAttr GetAttr<TAttr, T>(this T val) where TAttr : Attribute
{
return (TAttr)typeof(T)
.GetField(val.ToString())
?.GetCustomAttributes(typeof(TAttr), false)
?.FirstOrDefault();
}
}
Also, when working with reflection, it is important to cache for performance:
public static class AttributeExtensions
{
private class EnumMetadata
{
public CategoryAttribute CategoryAttribute { get; set; }
public DescriptionAttribute DescriptionAttribute { get; set; }
}
private class EnumMetadataCache<T> where T : Enum
{
private static readonly ConcurrentDictionary<T, EnumMetadata> MetadataCache = new ConcurrentDictionary<T, EnumMetadata>();
public static EnumMetadata GetMetadata(T item)
{
return MetadataCache.GetOrAdd(item, val =>
new EnumMetadata
{
CategoryAttribute = GetAttr<CategoryAttribute, T>(val),
DescriptionAttribute = GetAttr<DescriptionAttribute, T>(val)
}
);
}
}
public static string GetCategory<T>(this T val) where T : Enum
{
return EnumMetadataCache<T>.GetMetadata(val).CategoryAttribute?.Category ?? "";
}
public static string GetDescription<T>(this T val) where T : Enum
{
return EnumMetadataCache<T>.GetMetadata(val).DescriptionAttribute?.Description ?? "";
}
private static TAttr GetAttr<TAttr, T>(this T val) where TAttr : Attribute
{
return (TAttr)typeof(T)
.GetField(val.ToString())
?.GetCustomAttributes(typeof(TAttr), false)
?.FirstOrDefault();
}
}

How to find enum value using dynamic enum name & enum key name? [duplicate]

This question already has answers here:
how to get value of an unknown enum by name of enum and name of value?
(4 answers)
Closed 7 years ago.
I know How to find enum value if enum name & key are known at compile time. I have a situation where I get the enum name at runtime. any suggestion how to achieve this.
using System;
namespace EnumDemo
{
internal class Program
{
private static void Main(string[] args)
{
string[] ArrItemNames = Enum.GetNames(typeof (EnumClass.Colors));
foreach (string ItemName in ArrItemNames)
{
Console.WriteLine(
"{0} = {1:D}", ItemName,
Enum.Parse(typeof (EnumClass.Colors), ItemName));
}
Console.WriteLine();
var EnumVal = GetEnumValue("Colors", "Red");// Here I am expecting 1
Console.ReadKey();
}
//
public static int GetEnumValue(string EnumName, string ItemName)
{
return 0;
}
}
public class EnumClass
{
public enum Colors { Red = 1, Green = 2, Blue = 4, Yellow = 8 };
}
}
Note: My enum is inside a class.
Use the Enum.Parse function and convert it to int as described here
public static int GetValueOf(string enumName, string enumConst)
{
Type enumType = Type.GetType(enumName);
if (enumType == null)
{
throw new ArgumentException("Specified enum type could not be found", "enumName");
}
object value = Enum.Parse(enumType, enumConst);
return Convert.ToInt32(value);
}
If you are going to call this for your enum in your subclass you need to do it in this way:
public static void Main() {
{
Console.WriteLine(GetValueOf("YourNamespace.EnumClass+Colors", "Red"));
}
Since you know the type you could also use this directly as:
public static void Main() {
{
Console.WriteLine(GetValueOf(typeof(EnumClass.Colors), "Red"));
}
public static int GetValueOf(Type enumType, string enumConst)
{
object value = Enum.Parse(enumType, enumConst);
return Convert.ToInt32(value);
}
If I correctly understand the problem, the solution could be:
public static int GetEnumValue(string ItemName)
{
return (int)Enum.Parse(typeof(EnumClass.Colors), ItemName);
}

Alternative Names for C# enum

In Java, we can declare enums like so
public enum ChangeFlag
{
NEW("New"),
DELETED("Deleted"),
REVISED("Revised");
private final String text;
ChangeFlag(String text)
{
this.text = text;
}
public String toString()
{
return text;
}
}
Is there any elegant equivalent to this for C#?
Edit:
public static class FooExtensions
{
public static string GetDescription(this Foo #this)
{
switch (#this)
{
case Foo.Bar:
return "A bar";
}
}
}
Could you explain what the parameters in GetDescription(this Foo #this) mean?
I'm not used to seeing what this Foo #this refers to
You can use DescriptionAttribute:
public enum Foo
{
[Description("A bar")]
Bar
}
Which you would then extract via TypeDescriptor.GetAttributes or Type.GetCustomAttributes.
Or you could use extension methods:
public enum Foo
{
Bar
}
public static class FooExtensions
{
public static string GetDescription(this Foo #this)
{
switch (#this)
{
case Foo.Bar:
return "A bar";
}
}
}
// consuming code
var foo = Foo.Bar;
var description = foo.GetDescription();
The latter approach also gives you more control when it comes to localization, since you could always look up the description in a resource file, for example.
internal static class Program
{
private static void Main(string[] args)
{
ChangeFlag changeFlag = ChangeFlag.REVISED;
Console.WriteLine(changeFlag.GetDescription());
Console.Read();
}
public enum ChangeFlag
{
[Description("New")]
NEW,
[Description("Deleted")]
DELETED,
[Description("Revised")]
REVISED
}
}
public static class EnumExtensions
{
public static string GetDescription(this Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
if (fi != null)
{
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
return (attributes.Length > 0) ? attributes[0].Description : value.ToString();
}
return value.ToString();
}
}
A compact and fault-proof implementation variant, of the enum description getter extension method:
/// <exception cref="AmbiguousMatchException">More attributes found. </exception>
/// <exception cref="TypeLoadException">Cannot load custom attribute.</exception>
public static string GetDescription(this Enum value)
{
Type type = value.GetType();
string enumName = Enum.GetName(type, value);
if (enumName == null)
{
return null; // or return string.Empty;
}
FieldInfo typeField = type.GetField(enumName);
if (typeField == null)
{
return null; // or return string.Empty;
}
var attribute = Attribute.GetCustomAttribute(typeField, typeof(DescriptionAttribute));
return (attribute as DescriptionAttribute)?.Description; // ?? string.Empty maybe added
}
Also a comparison extension method (which uses the upper) for the description may be useful:
public static bool DescriptionEquals(this Enum value, string inputForComparison,
StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)
{
string description;
try
{
description = value.GetDescription();
}
catch (Exception ex) when (ex is AmbiguousMatchException || ex is TypeLoadException)
{
return false;
}
if (description == null || inputForComparison == null)
{
return false;
}
return inputForComparison.Equals(description, comparisonType);
// || inputForComparison.Equals(value.ToString(), comparisonType); may be added
}

Generics, enums and custom attributes - is it possible?

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

Categories

Resources