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