C#: "Pretty" type name function? - c#

The name properties of System.Type class return a strange result in case of generic types. Is there a way to get the type name in a format closer to the way I specified it?
Example: typeof(List<string>).OriginalName == "List<string>"

The problem with "pretty" names is they are different depending on the language you are using. Imagine the surprise of a VB.NET developer if OriginalName returned C# syntax.
However, it's pretty fairly easy to make this yourself:
private static string PrettyName(Type type)
{
if (type.GetGenericArguments().Length == 0)
{
return type.Name;
}
var genericArguments = type.GetGenericArguments();
var typeDefinition = type.Name;
var unmangledName = typeDefinition.Substring(0, typeDefinition.IndexOf("`"));
return unmangledName + "<" + String.Join(",", genericArguments.Select(PrettyName)) + ">";
}
This will recursively resolve the unmanaged name, so that if you have something like Dictionary<string, IList<string>> it should still work.

I used CodeDomProvider to convert to c#:
public static string GetOriginalName(this Type type)
{
string TypeName = type.FullName.Replace(type.Namespace + ".", "");//Removing the namespace
var provider = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("CSharp"); //You can also use "VisualBasic"
var reference = new System.CodeDom.CodeTypeReference(TypeName);
return provider.GetTypeOutput(reference);
}

Like Harold Hoyer's answer but including nullables and a few more built-in types:
/// <summary>
/// Get full type name with full namespace names
/// </summary>
/// <param name="type">
/// The type to get the C# name for (may be a generic type or a nullable type).
/// </param>
/// <returns>
/// Full type name, fully qualified namespaces
/// </returns>
public static string CSharpName(this Type type)
{
Type nullableType = Nullable.GetUnderlyingType(type);
string nullableText;
if (nullableType != null)
{
type = nullableType;
nullableText = "?";
}
else
{
nullableText = string.Empty;
}
if (type.IsGenericType)
{
return string.Format(
"{0}<{1}>{2}",
type.Name.Substring(0, type.Name.IndexOf('`')),
string.Join(", ", type.GetGenericArguments().Select(ga => ga.CSharpName())),
nullableText);
}
switch (type.Name)
{
case "String":
return "string";
case "Int32":
return "int" + nullableText;
case "Decimal":
return "decimal" + nullableText;
case "Object":
return "object" + nullableText;
case "Void":
return "void" + nullableText;
default:
return (string.IsNullOrWhiteSpace(type.FullName) ? type.Name : type.FullName) + nullableText;
}
}

Here is my implementation. It was created to describe methods, so it handles the ref and out keywords.
private static Dictionary<Type, string> shorthandMap = new Dictionary<Type, string>
{
{ typeof(Boolean), "bool" },
{ typeof(Byte), "byte" },
{ typeof(Char), "char" },
{ typeof(Decimal), "decimal" },
{ typeof(Double), "double" },
{ typeof(Single), "float" },
{ typeof(Int32), "int" },
{ typeof(Int64), "long" },
{ typeof(SByte), "sbyte" },
{ typeof(Int16), "short" },
{ typeof(String), "string" },
{ typeof(UInt32), "uint" },
{ typeof(UInt64), "ulong" },
{ typeof(UInt16), "ushort" },
};
private static string CSharpTypeName(Type type, bool isOut = false)
{
if (type.IsByRef)
{
return String.Format("{0} {1}", isOut ? "out" : "ref", CSharpTypeName(type.GetElementType()));
}
if (type.IsGenericType)
{
if (type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return String.Format("{0}?", CSharpTypeName(Nullable.GetUnderlyingType(type)));
}
else
{
return String.Format("{0}<{1}>", type.Name.Split('`')[0],
String.Join(", ", type.GenericTypeArguments.Select(a => CSharpTypeName(a)).ToArray()));
}
}
if (type.IsArray)
{
return String.Format("{0}[]", CSharpTypeName(type.GetElementType()));
}
return shorthandMap.ContainsKey(type) ? shorthandMap[type] : type.Name;
}
The calling code looks like this:
string line = String.Format("{0}.{1}({2})",
method.DeclaringType.Name,
method.Name,
String.Join(", ", method.GetParameters().Select(p => CSharpTypeName(p.ParameterType, p.IsOut) + " " + p.Name).ToArray()));
Where method is a MethodInfo instance.
One note: I didn't have a need to describe any multi-dimensional array types, so I didn't bother implementing description for that, but it would be fairly easy to add by calling type.GetArrayRank().

You have to write this yourself. Keep in mind that Type.Name etc. are invoking methods that live in the CLR and can be invoked from multiple languages. This is why they don't come back looking like C# or VB or the language the caller was coded in, but instead looking like the CLR representation.
Note further that string and what not are aliases for CLR types like System.String. Again, this plays a role in the formatting that you see.
It's not hard to do using reflection, but I question the value of it.

A minimal work solution that leverages CodeDomProvider is to control how the CodeTypeReference instance is built in the first place. There are special cases only for generic types and multi-rank arrays, so we only have to care about those:
static CodeTypeReference CreateTypeReference(Type type)
{
var typeName = (type.IsPrimitive || type == typeof(string)) ? type.FullName : type.Name;
var reference = new CodeTypeReference(typeName);
if (type.IsArray)
{
reference.ArrayElementType = CreateTypeReference(type.GetElementType());
reference.ArrayRank = type.GetArrayRank();
}
if (type.IsGenericType)
{
foreach (var argument in type.GetGenericArguments())
{
reference.TypeArguments.Add(CreateTypeReference(argument));
}
}
return reference;
}
Using this modified factory method, it is then possible to use the appropriate code provider to get pretty typing, like so:
using (var provider = new CSharpCodeProvider())
{
var reference = CreateTypeReference(typeof(IObservable<IEnumerable<Tuple<int?, string>>>[,]));
var output = provider.GetTypeOutput(reference);
Console.WriteLine(output);
}
The above code returns IObservable<IEnumerable<Tuple<Nullable<int>, string>>>[,]. The only special case that is not handled well are Nullable types but this is really more a fault of the CodeDomProvider than anything else.

First: Kudos to Navid for wheel reinvention avoidance. I would upvote if I could.
Here are a few points to add, if anyone goes down this path (at least for VS10/.Net 4):
* Try using one of the variants of CodeTypeReference with Type arguments. This avoids a number of pitfalls of using string type names (such as trailing &) and means you get back bool instead of System.Boolean etc. You do get back the full namespace for a lot of types like this but you can always get rid of the namespace part later.
* Simple Nullables tend to come back in the form System.Nullable<int> rather than int? - You can convert to the nicer syntax with a regex on the answer such as:
const string NullablePattern = #"System.Nullable<(?<nulledType>[\w\.]+)>";
const string NullableReplacement = #"${nulledType}?";
answer = Regex.Replace(answer, NullablePattern, NullableReplacement);
* The Type of a method argument like out T? gives a very opaque string. If anyone has an elegant way of dealing with things like this I would love to know about it.Hopefully this all becomes very easy with Roslyn.

as in your example you can expect the type so you can try that
public class test<T> where T : class
{
public List<String> tt
{
get;
set;
}
}
///////////////////////////
test<List<String>> tt = new test<List<String>>();
if(tt.GetType().FullName.Contains(TypeOf(List<String>).FullName))
{
//do something
}
else
{
//do something else
}

I understand that you want to compare types.
The best way to do this is...
myVar is List<string> or
myVar.GetType() == myOtherVar.GetType()
If you don't need this... please disregard my answer.

I understood, that I have to write this myself. Here is my solution (it is actually a bit more than asked for). It is, probably, helpfull.
using System.Reflection;
using HWClassLibrary.Debug;
using System.Collections.Generic;
using System.Linq;
using System;
namespace HWClassLibrary.Helper
{
public static class TypeNameExtender
{
private static IEnumerable<Type> _referencedTypesCache;
public static void OnModuleLoaded() { _referencedTypesCache = null; }
public static string PrettyName(this Type type)
{
if(type == typeof(int))
return "int";
if(type == typeof(string))
return "string";
var result = PrettyTypeName(type);
if(type.IsGenericType)
result = result + PrettyNameForGeneric(type.GetGenericArguments());
return result;
}
private static string PrettyTypeName(Type type)
{
var result = type.Name;
if(type.IsGenericType)
result = result.Remove(result.IndexOf('`'));
if (type.IsNested && !type.IsGenericParameter)
return type.DeclaringType.PrettyName() + "." + result;
if(type.Namespace == null)
return result;
var conflictingTypes = ReferencedTypes
.Where(definedType => definedType.Name == type.Name && definedType.Namespace != type.Namespace)
.ToArray();
var namespaceParts = type.Namespace.Split('.').Reverse().ToArray();
var namespacePart = "";
for(var i = 0; i < namespaceParts.Length && conflictingTypes.Length > 0; i++)
{
namespacePart = namespaceParts[i] + "." + namespacePart;
conflictingTypes = conflictingTypes
.Where(conflictingType => (conflictingType.Namespace + ".").EndsWith(namespacePart))
.ToArray();
}
return namespacePart + result;
}
private static IEnumerable<Type> ReferencedTypes
{
get
{
if(_referencedTypesCache == null)
_referencedTypesCache = Assembly.GetEntryAssembly().GetReferencedTypes();
return _referencedTypesCache;
}
}
private static string PrettyNameForGeneric(Type[] types)
{
var result = "";
var delim = "<";
foreach(var t in types)
{
result += delim;
delim = ",";
result += t.PrettyName();
}
return result + ">";
}
}
}

I do it like this ..
public static class TypeExtensions {
public static String GetName(this Type t) {
String readable;
#if PREVENT_RECURSION
if(m_names.TryGetValue(t, out readable)) {
return readable;
}
#endif
var tArgs = t.IsGenericType ? t.GetGenericArguments() : Type.EmptyTypes;
var name = t.Name;
var format = Regex.Replace(name, #"`\d+.*", "")+(t.IsGenericType ? "<?>" : "");
var names = tArgs.Select(x => x.IsGenericParameter ? "" : GetName(x));
readable=String.Join(String.Join(",", names), format.Split('?'));
#if PREVENT_RECURSION
m_names.Add(t, readable);
#endif
return readable;
}
static readonly Dictionary<Type, String> m_names = new Dictionary<Type, String> { };
}
where PREVENT_RECURSION should be defined true if you don't want the type in generic type arguments be resolved recursively every time, just take from the cache dictionary; leave it undefined of false if you don't care that.

Combined a few answers, added support for nested types and array ranks, and turned it into an extension method with cached resolved names.
/// <summary>
/// Extension methods for <see cref="Type"/>.
/// </summary>
public static class TypeExtensions
{
/// <summary>
/// Dictionary of type names.
/// </summary>
private static readonly ConcurrentDictionary<Type, string> typeNames;
/// <summary>
/// Initializes static members of the <see cref="TypeExtensions"/> class.
/// </summary>
static TypeExtensions()
{
typeNames = new ConcurrentDictionary<Type, string>
{
[typeof(bool)] = "bool",
[typeof(byte)] = "byte",
[typeof(char)] = "char",
[typeof(decimal)] = "decimal",
[typeof(double)] = "double",
[typeof(float)] = "float",
[typeof(int)] = "int",
[typeof(long)] = "long",
[typeof(sbyte)] = "sbyte",
[typeof(short)] = "short",
[typeof(string)] = "string",
[typeof(uint)] = "uint",
[typeof(ulong)] = "ulong",
[typeof(ushort)] = "ushort"
};
}
/// <summary>
/// Gets the type name with generics and array ranks resolved.
/// </summary>
/// <param name="type">
/// The type whose name to resolve.
/// </param>
/// <returns>
/// The resolved type name.
/// </returns>
public static string ToCSTypeName(this Type type)
{
return typeNames.GetOrAdd(type, GetPrettyTypeName);
}
/// <summary>
/// Gets the type name as it would be written in C#
/// </summary>
/// <param name="type">
/// The type whose name is to be written.
/// </param>
/// <returns>
/// The type name as it is written in C#
/// </returns>
private static string GetPrettyTypeName(Type type)
{
var typeNamespace = type.DeclaringType != null ? ToCSTypeName(type.DeclaringType) : type.Namespace;
if (type.IsGenericType)
{
if (type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return $"{ToCSTypeName(Nullable.GetUnderlyingType(type))}?";
}
var typeList = string.Join(", ", type.GenericTypeArguments.Select(ToCSTypeName).ToArray());
var typeName = type.Name.Split('`')[0];
return $"{typeNamespace}.{typeName}<{typeList}>";
}
if (type.IsArray)
{
var arrayRank = string.Empty.PadLeft(type.GetArrayRank() - 1, ',');
var elementType = ToCSTypeName(type.GetElementType());
return $"{elementType}[{arrayRank}]";
}
return $"{typeNamespace}.{type.Name}";
}
}

public static string pretty_name( Type type, int recursion_level = -1, bool expand_nullable = false )
{
if( type.IsArray )
{
return $"{pretty_name( type.GetElementType(), recursion_level, expand_nullable )}[]";
}
if( type.IsGenericType )
{
// find generic type name
var gen_type_name = type.GetGenericTypeDefinition().Name;
var index = gen_type_name.IndexOf( '`' );
if( index != -1 )
gen_type_name = gen_type_name.Substring( 0, index );
// retrieve generic type aguments
var arg_names = new List<string>();
var gen_type_args = type.GetGenericArguments();
foreach( var gen_type_arg in gen_type_args )
{
arg_names.Add(
recursion_level != 0
? pretty_name( gen_type_arg, recursion_level - 1, expand_nullable )
: "?" );
}
// if type is nullable and want compact notation '?'
if( !expand_nullable && Nullable.GetUnderlyingType( type ) != null )
return $"{arg_names[ 0 ]}?";
// compose common generic type format "T<T1, T2, ...>"
return $"{gen_type_name}<{string.Join( ", ", arg_names )}>";
}
return type.Name;
}
My two cents:
Everything is done through the Type interface
No Regex
No extra objects created except for the list that holds generic argument names
Supports infinite recursion or recursion to a certain level (or no recursion at all!)
Supports nullable types (both formats "Nullable<>" and "?")
Supports ranked arrays

Related

Get enum value by name attribute [duplicate]

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

generic type conversion in C#

Is there any way the following code can be improved. I'm aware of the non nullable reference in C# 8.0 and was thinking either that or any other way they code below could be made more robust and better in general.
This method is called for converting xml data before insertion in a database Through entity framework core. Any way these tools can be used to improve this code is welcomed.
public object Convert(string value, Type toType)
{
try
{
if (toType == typeof(short))
{
return short.Parse(value);
}
if (toType == typeof(short?))
{
if (string.IsNullOrEmpty(value))
{
return null;
}
return short.Parse(value);
}
if (toType == typeof(int))
{
return int.Parse(value);
}
if (toType == typeof(int?))
{
if (string.IsNullOrEmpty(value))
{
return null;
}
return int.Parse(value);
}
if (toType == typeof(decimal))
{
return decimal.Parse(value);
}
if (toType == typeof(decimal?))
{
if (string.IsNullOrEmpty(value))
{
return null;
}
return decimal.Parse(value);
}
if (toType == typeof(DateTime))
{
return DateTime.Parse(value);
}
if (toType == typeof(DateTime?))
{
if (string.IsNullOrEmpty(value))
{
return null;
}
return DateTime.Parse(value);
}
throw new NotSupportedException($"No conversion defined for type:'{toType}'");
}
catch (System.FormatException excp)
{
throw new ConversionException($"Value:'{value}' could not be converted to:'{toType.Name}'", excp);
}
}
Many thanks in advance
The only thing I can offer is to improve robustness by using .TryParse() for the parsing instead of .Parse()
class Program
{
static void Main(string[] args)
{
var i = Parse<int>("100");
var x = Parse<double>("3.1417");
var s = Parse<string>("John");
var d = Parse<Decimal>("1234.56");
var f = Parse<DateTime>("4/1/2044");
var q = Parse<byte>("4A");
Decimal? p = Parse<decimal>("Not Decimal");
}
public static dynamic Parse<T>(string text)
{
var toType = typeof(T);
if (toType == typeof(int))
{
if (int.TryParse(text, out int x))
{
return x;
}
}
else if (toType == typeof(short))
{
if (short.TryParse(text, out short x))
{
return x;
}
}
else if (toType == typeof(double))
{
if (double.TryParse(text, out double x))
{
return x;
}
}
else if (toType == typeof(decimal))
{
if (decimal.TryParse(text, out decimal x))
{
return x;
}
}
else if (toType == typeof(DateTime))
{
if (DateTime.TryParse(text, out DateTime x))
{
return x;
}
}
else if (toType == typeof(byte))
{
if (byte.TryParse(text, System.Globalization.NumberStyles.HexNumber, null, out byte x))
{
return x;
}
}
else if (toType == typeof(string))
{
return text;
}
return null;
}
}
IMO the main improvement here would be to remove all boxing. Which means using generics throughout. Now, there's a complication there: with generics, it is hard to change types without with boxing (to convince the compiler you know what you're doing), or using meta-programming. So: I'd lean towards the latter. Something like:
public static T Convert<T>(string input)
=> TypeCache<T>.Convert(input);
private static TypeCache<T> {
public static readonly Func<string, T> Convert
= CreateConverter<T>();
}
private static Func<string, T> CreateConverter<T>()
{...}
The magic all happens in that last method. The problem is: it isn't trivial. The simplest approach should be to use reflection to discover a suitable parse method, then manually construct an Expression<Func<string, T>> by linking appropriate Expression nodes to repreresent the operation, then call Compile() to get a delegate. Another approach is to go straight to DynamicMethod and ILGenerator. Both are advanced topics.
This is the code I wrote and used in my company's project really well.
You can try to use this:
/// <summary>
/// Method : Simply Universal Type Converter
/// Requirement : C# 7.0+
/// Created by : Byungho Park(Tapegawui) in South Korea.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="val">Original value</param>
/// <param name="rfrom">(Optional)Character(s) want to replace from</param>
/// <param name="rto">(Optional)Character(s) will be replace to</param>
/// <returns></returns>
public static T Cast<T>(dynamic val, string rfrom = "", string rto = "") where T : IConvertible
{
try
{
// Convert null to empty else 0
if (val is null || val.Equals(DBNull.Value))
{
if (typeof(T) == typeof(string) || typeof(T) == typeof(DateTime))
{
val = string.Empty;
}
else if (typeof(T) == typeof(bool))
{
val = false;
}
else
{
val = 0;
}
}
else
{
// Replace string given parameter from a to b
if (typeof(T) == typeof(string) && rfrom == "" & rto.Length > 0)
{
if (val.ToString().Length == 0)
{
val = rto;
}
}
else if (typeof(T) == typeof(string) && rto.Length > 0)
{
val = (string)val.ToString().Replace(rfrom, rto);
}
}
// Convert type on this block finally
return (T)Convert.ChangeType(val, typeof(T));
}
catch (Exception)
{
return default(T);
}
}
And usage examples:
using System;
int vint = 10;
int vint2 = vint;
string vstr = "1000000";
string vdcm = "123456789123456789";
for (int i = 1; i <= vint; i++)
{
vint2 += i;
}
Console.WriteLine($"Adding int with loop : {vint2} from {vint}\n");
string tint = Cast<string>(vint);
for (int i = 1; i <= vint; i++)
{
tint += i;
}
Console.WriteLine($"Adding string with loop : {tint} from {vint}\n");
long tlong = Cast<long>(vstr);
tlong *= tlong;
Console.WriteLine($"Multiply long : {tlong} from {vstr}\n");
double tdbl = Cast<double>(vdcm);
for (int i = 1; i <= vint; i++)
{
tdbl *= i;
}
Console.WriteLine($"Multiply double with loop : {tdbl} from {vdcm}\n");
decimal tdcm = Cast<decimal>(vdcm);
for (int i = 1; i <= vint; i++)
{
tdcm *= i;
}
Console.WriteLine($"Multiply decimal with loop : {tdcm} from {vdcm}\n");
string ns = null;
Console.WriteLine($"Null string : {Cast<string>(ns)}\n");
int? ni = null;
Console.WriteLine($"Null int : {Cast<int>(ni)}\n");
long? nl = null;
Console.WriteLine($"Null long : {Cast<long>(nl)}\n");
double? ndbl = null;
Console.WriteLine($"Null double : {Cast<double>(ndbl)}\n");
decimal? nd = null;
Console.WriteLine($"Null decimal : {Cast<decimal>(nd)}\n");
string tb = "true";
Console.WriteLine($"Convert string to boolean : {Cast<bool>(tb)}\n");
bool? nb = null;
Console.WriteLine($"Null boolean : {Cast<bool>(nb)}\n");
// -----------------------
// From Microsoft examples
double d = -2.345;
int t = Cast<int>(d);
Console.WriteLine($"The double value {d} when converted to an int becomes {t}\n");
string s = "98/12/12";
DateTime dt = Cast<DateTime>(s);
Console.WriteLine($"The string value {s} when converted to a Date becomes {dt}\n");
// -----------------------
// ------------------------------------------
// Replace some character(s) with string type
string rs = "Replace this string with x to y.";
Console.WriteLine($"{Cast<string>(rs, " ", "_")}\n");
Console.WriteLine($"{Cast<string>("abcd", "", "abc")}\n");
Console.WriteLine($"{Cast<string>("", "", "abc")}\n");
string rs3 = "Replace this string from x to y.";
string ts = "string";
Console.WriteLine($"{Cast<string>(rs3, ts, ts.ToUpper())}\n");
Console.WriteLine($"Replace int character with string : {Cast<string>(vstr, "0", "1")}\n");
// ------------------------------------------
Console.WriteLine("Press any key to close...");
Console.ReadKey();
In addition, output results:
Adding int with loop : 65 from 10
Adding string with loop : 1012345678910 from 10
Multiply long : 1000000000000 from 1000000
Multiply double with loop : 4.479999963712E+23 from 123456789123456789
Multiply decimal with loop : 447999996371199995923200 from 123456789123456789
Null string :
Null int : 0
Null long : 0
Null double : 0
Null decimal : 0
Convert string to boolean : True
Null boolean : False
The double value -2.345 when converted to an int becomes -2
The string value 98/12/12 when converted to a Date becomes 1998-12-12 오전 12:00:00
Replace_this_string_with_x_to_y.
abcd
abc
Replace this STRING from x to y.
Replace int character with string : 1111111
Press any key to close...
public static class StringExtensions
{
public static TDest ConvertStringTo<TDest>(this string src)
{
if (src == null)
{
return default(TDest);
}
try
{
return ChangeType<TDest>(src);
}
catch
{
return default(TDest);
}
}
private static T ChangeType<T>(string value)
{
var t = typeof(T);
if (t.GetTypeInfo().IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
t = Nullable.GetUnderlyingType(t);
}
return (T)Convert.ChangeType(value, t);
}
}
Using runtime infrastructure to determine types and perform conversions between them as proposed by the other answers is very convenient and probably what you are looking for.
If, however, you need more control over your conversion (or rather parsing), e.g. because you get weird input formats that require pre-processing, may I suggest the following class.
It lets you provide a parser method for each type you register. The types from your question with their nullable cousins come pre-registered in the constructor, but you can also add any other method to the dictionary as your input data requires:
public delegate bool Parser<T>(string input, out T output);
public class Parsers
{
private delegate bool UntypedParser(string input, out object output);
private Dictionary<Type, UntypedParser> _parsersByType = new Dictionary<Type, UntypedParser>();
/// <summary>
/// Creates a <see cref="Parsers"/> instance pre-populated with parsers for the most common types.
/// </summary>
public static Parsers CreateDefault()
{
Parsers result = new Parsers();
result.AddParser<string>((string input, out string output) => { output = input; return true; });
result.AddParserForNullable<bool>(bool.TryParse);
result.AddParserForNullable<byte>(byte.TryParse);
result.AddParserForNullable<DateTime>(DateTime.TryParse);
result.AddParserForNullable<decimal>(decimal.TryParse);
result.AddParserForNullable<double>(double.TryParse);
result.AddParserForNullable<float>(float.TryParse);
result.AddParserForNullable<int>(int.TryParse);
result.AddParserForNullable<short>(short.TryParse);
return result;
}
/// <summary>
/// Registers a parser for the given type T
/// </summary>
public void AddParser<T>(Parser<T> parser)
{
_parsersByType[typeof(T)] = (string input, out object output) => ParseObject(parser, input, out output);
}
/// <summary>
/// Registers a parser for the given type T as well as <see cref="Nullable{T}"/>
/// </summary>
public void AddParserForNullable<T>(Parser<T> parser)
where T : struct
{
_parsersByType[typeof(T)] = (string input, out object output) => ParseObject(parser, input, out output);
_parsersByType[typeof(T?)] = (string input, out object output) => ParseNullable(parser, input, out output);
}
/// <summary>
/// For nullable types, return null when the input is an empty string or null.
/// </summary>
/// <remarks>This is not called for the string-parser. Meaning an empty string is not parsed into a null value.</remarks>
private bool ParseNullable<T>(Parser<T> parser, string input, out object output)
where T : struct
{
bool result;
if (string.IsNullOrEmpty(input))
{
result = true;
output = null;
}
else
{
result = ParseObject(parser, input, out output);
}
return result;
}
/// <summary>
/// Helper method to convert the typed output into an object (possibly boxing the value)
/// </summary>
private bool ParseObject<T>(Parser<T> parser, string input, out object output)
{
bool result = parser(input, out T typedOutput);
output = typedOutput;
return result;
}
/// <summary>
/// Finds the parser for the given target type and uses it to parse the input.
/// </summary>
public object Parse<T>(string input)
{
Type targetType = typeof(T);
object result;
if (!_parsersByType.TryGetValue(targetType, out UntypedParser parser))
{
throw new ArgumentException($"No parser defined for type '{targetType}'.");
}
else if (!parser(input, out result))
{
throw new ArgumentException($"Cannot parse '{targetType}' from input '{input}'.");
}
return result;
}
}

Get the type name

How i can get full right name of generic type?
For example:
This code
typeof(List<string>).Name
return
List`1
instead of
List<string>
How to get a right name?
typeof(List<string>).ToString()
returns System.Collections.Generic.List`1[System.String] but i want to get initial name:
List<string>
Is it real?
Use the FullName property.
typeof(List<string>).FullName
That will give you the namespace + class + type parameters.
What you are asking for is a C# specific syntax. As far as .NET is concerned, this is proper:
System.Collections.Generic.List`1[System.String]
So to get what you want, you'd have to write a function to build it the way you want it. Perhaps like so:
static string GetCSharpRepresentation( Type t, bool trimArgCount ) {
if( t.IsGenericType ) {
var genericArgs = t.GetGenericArguments().ToList();
return GetCSharpRepresentation( t, trimArgCount, genericArgs );
}
return t.Name;
}
static string GetCSharpRepresentation( Type t, bool trimArgCount, List<Type> availableArguments ) {
if( t.IsGenericType ) {
string value = t.Name;
if( trimArgCount && value.IndexOf("`") > -1 ) {
value = value.Substring( 0, value.IndexOf( "`" ) );
}
if( t.DeclaringType != null ) {
// This is a nested type, build the nesting type first
value = GetCSharpRepresentation( t.DeclaringType, trimArgCount, availableArguments ) + "+" + value;
}
// Build the type arguments (if any)
string argString = "";
var thisTypeArgs = t.GetGenericArguments();
for( int i = 0; i < thisTypeArgs.Length && availableArguments.Count > 0; i++ ) {
if( i != 0 ) argString += ", ";
argString += GetCSharpRepresentation( availableArguments[0], trimArgCount );
availableArguments.RemoveAt( 0 );
}
// If there are type arguments, add them with < >
if( argString.Length > 0 ) {
value += "<" + argString + ">";
}
return value;
}
return t.Name;
}
For these types (with true as 2nd param):
typeof( List<string> ) )
typeof( List<Dictionary<int, string>> )
It returns:
List<String>
List<Dictionary<Int32, String>>
In general though, I'd bet you probably don't need to have the C# representation of your code and perhaps if you do, some format better than the C# syntax would be more appropriate.
You could use this:
public static string GetTypeName(Type t) {
if (!t.IsGenericType) return t.Name;
if (t.IsNested && t.DeclaringType.IsGenericType) throw new NotImplementedException();
string txt = t.Name.Substring(0, t.Name.IndexOf('`')) + "<";
int cnt = 0;
foreach (Type arg in t.GetGenericArguments()) {
if (cnt > 0) txt += ", ";
txt += GetTypeName(arg);
cnt++;
}
return txt + ">";
}
For example:
static void Main(string[] args) {
var obj = new Dictionary<string, Dictionary<HashSet<int>, int>>();
string s = GetTypeName(obj.GetType());
Console.WriteLine(s);
Console.ReadLine();
}
Output:
Dictionary<String, Dictionary<HashSet<Int32>, Int32>>
If you have an instance of the list, you can call .ToString() and get the following
System.Collections.Generic.List`1[System.String]
This is in addition to the methods provided by the other answers directly against the type rather than the instance.
Edit: On your edit, I do not believe it is possible without providing your own parsing method, as List<string> is C# shorthand for how the type is implemented, sort of like if you wrote typeof(int).ToString(), what is captured is not "int" but the CTS name, System.Int32.
Here's my implementation, which benefited from #Hans's answer above and #Jack's answer on a duplicate question.
public static string GetCSharpName( this Type type )
{
string result;
if ( primitiveTypes.TryGetValue( type, out result ) )
return result;
else
result = type.Name.Replace( '+', '.' );
if ( !type.IsGenericType )
return result;
else if ( type.IsNested && type.DeclaringType.IsGenericType )
throw new NotImplementedException();
result = result.Substring( 0, result.IndexOf( "`" ) );
return result + "<" + string.Join( ", ", type.GetGenericArguments().Select( GetCSharpName ) ) + ">";
}
static Dictionary<Type, string> primitiveTypes = new Dictionary<Type, string>
{
{ typeof(bool), "bool" },
{ typeof(byte), "byte" },
{ typeof(char), "char" },
{ typeof(decimal), "decimal" },
{ typeof(double), "double" },
{ typeof(float), "float" },
{ typeof(int), "int" },
{ typeof(long), "long" },
{ typeof(sbyte), "sbyte" },
{ typeof(short), "short" },
{ typeof(string), "string" },
{ typeof(uint), "uint" },
{ typeof(ulong), "ulong" },
{ typeof(ushort), "ushort" },
};
Another way to get a nice type name by using an extension:
typeof(Dictionary<string, Dictionary<decimal, List<int>>>).CSharpName();
// output is:
// Dictionary<String, Dictionary<Decimal, List<Int32>>>
The Extension Code:
public static class TypeExtensions
{
public static string CSharpName(this Type type)
{
string typeName = type.Name;
if (type.IsGenericType)
{
var genArgs = type.GetGenericArguments();
if (genArgs.Count() > 0)
{
typeName = typeName.Substring(0, typeName.Length - 2);
string args = "";
foreach (var argType in genArgs)
{
string argName = argType.Name;
if (argType.IsGenericType)
argName = argType.CSharpName();
args += argName + ", ";
}
typeName = string.Format("{0}<{1}>", typeName, args.Substring(0, args.Length - 2));
}
}
return typeName;
}
}
typeof(List<string>).ToString()
An improvement on Adam Sills's answer that works with non-generic nested types, and generic type definitions:
public class TypeNameStringExtensions
{
public static string GetCSharpRepresentation(Type t)
{
return GetCSharpRepresentation(t, new Queue<Type>(t.GetGenericArguments()));
}
static string GetCSharpRepresentation(Type t, Queue<Type> availableArguments)
{
string value = t.Name;
if (t.IsGenericParameter)
{
return value;
}
if (t.DeclaringType != null)
{
// This is a nested type, build the parent type first
value = GetCSharpRepresentation(t.DeclaringType, availableArguments) + "+" + value;
}
if (t.IsGenericType)
{
value = value.Split('`')[0];
// Build the type arguments (if any)
string argString = "";
var thisTypeArgs = t.GetGenericArguments();
for (int i = 0; i < thisTypeArgs.Length && availableArguments.Count > 0; i++)
{
if (i != 0) argString += ", ";
argString += GetCSharpRepresentation(availableArguments.Dequeue());
}
// If there are type arguments, add them with < >
if (argString.Length > 0)
{
value += "<" + argString + ">";
}
}
return value;
}
[TestCase(typeof(List<string>), "List<String>")]
[TestCase(typeof(List<Dictionary<int, string>>), "List<Dictionary<Int32, String>>")]
[TestCase(typeof(Stupid<int>.Stupider<int>), "Stupid<Int32>+Stupider<Int32>")]
[TestCase(typeof(Dictionary<int, string>.KeyCollection), "Dictionary<Int32, String>+KeyCollection")]
[TestCase(typeof(Nullable<Point>), "Nullable<Point>")]
[TestCase(typeof(Point?), "Nullable<Point>")]
[TestCase(typeof(TypeNameStringExtensions), "TypeNameStringExtensions")]
[TestCase(typeof(Another), "TypeNameStringExtensions+Another")]
[TestCase(typeof(G<>), "TypeNameStringExtensions+G<T>")]
[TestCase(typeof(G<string>), "TypeNameStringExtensions+G<String>")]
[TestCase(typeof(G<Another>), "TypeNameStringExtensions+G<TypeNameStringExtensions+Another>")]
[TestCase(typeof(H<,>), "TypeNameStringExtensions+H<T1, T2>")]
[TestCase(typeof(H<string, Another>), "TypeNameStringExtensions+H<String, TypeNameStringExtensions+Another>")]
[TestCase(typeof(Another.I<>), "TypeNameStringExtensions+Another+I<T3>")]
[TestCase(typeof(Another.I<int>), "TypeNameStringExtensions+Another+I<Int32>")]
[TestCase(typeof(G<>.Nested), "TypeNameStringExtensions+G<T>+Nested")]
[TestCase(typeof(G<string>.Nested), "TypeNameStringExtensions+G<String>+Nested")]
[TestCase(typeof(A<>.C<>), "TypeNameStringExtensions+A<B>+C<D>")]
[TestCase(typeof(A<int>.C<string>), "TypeNameStringExtensions+A<Int32>+C<String>")]
public void GetCSharpRepresentation_matches(Type type, string expected)
{
string actual = GetCSharpRepresentation(type);
Assert.AreEqual(expected, actual);
}
public class G<T>
{
public class Nested { }
}
public class A<B>
{
public class C<D> { }
}
public class H<T1, T2> { }
public class Another
{
public class I<T3> { }
}
}
public class Stupid<T1>
{
public class Stupider<T2>
{
}
}
I also chose to forgo his trimArgCount, as I can't see when that would be useful, and to use a Queue<Type> since that was the intent (pulling items off the front while they exist).
I had problems with the other answers in some instances, i.e. with arrays, so I ended up writing yet another one. I don't use the text from Type.Name or similar except to get the plain name of the types, because I don't know if the format is guaranteed to be the same across different .Net versions or with other implementations of the libraries (I assume it isn't).
/// <summary>
/// For the given type, returns its representation in C# code.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="genericArgs">Used internally, ignore.</param>
/// <param name="arrayBrackets">Used internally, ignore.</param>
/// <returns>The representation of the type in C# code.</returns>
public static string GetTypeCSharpRepresentation(Type type, Stack<Type> genericArgs = null, StringBuilder arrayBrackets = null)
{
StringBuilder code = new StringBuilder();
Type declaringType = type.DeclaringType;
bool arrayBracketsWasNull = arrayBrackets == null;
if (genericArgs == null)
genericArgs = new Stack<Type>(type.GetGenericArguments());
int currentTypeGenericArgsCount = genericArgs.Count;
if (declaringType != null)
currentTypeGenericArgsCount -= declaringType.GetGenericArguments().Length;
Type[] currentTypeGenericArgs = new Type[currentTypeGenericArgsCount];
for (int i = currentTypeGenericArgsCount - 1; i >= 0; i--)
currentTypeGenericArgs[i] = genericArgs.Pop();
if (declaringType != null)
code.Append(GetTypeCSharpRepresentation(declaringType, genericArgs)).Append('.');
if (type.IsArray)
{
if (arrayBrackets == null)
arrayBrackets = new StringBuilder();
arrayBrackets.Append('[');
arrayBrackets.Append(',', type.GetArrayRank() - 1);
arrayBrackets.Append(']');
Type elementType = type.GetElementType();
code.Insert(0, GetTypeCSharpRepresentation(elementType, arrayBrackets : arrayBrackets));
}
else
{
code.Append(new string(type.Name.TakeWhile(c => char.IsLetterOrDigit(c) || c == '_').ToArray()));
if (currentTypeGenericArgsCount > 0)
{
code.Append('<');
for (int i = 0; i < currentTypeGenericArgsCount; i++)
{
code.Append(GetTypeCSharpRepresentation(currentTypeGenericArgs[i]));
if (i < currentTypeGenericArgsCount - 1)
code.Append(',');
}
code.Append('>');
}
if (declaringType == null && !string.IsNullOrEmpty(type.Namespace))
{
code.Insert(0, '.').Insert(0, type.Namespace);
}
}
if (arrayBracketsWasNull && arrayBrackets != null)
code.Append(arrayBrackets.ToString());
return code.ToString();
}
I have tested it with crazy types like this, and so far it has worked perfectly:
class C
{
public class D<D1, D2>
{
public class E
{
public class K<R1, R2, R3>
{
public class P<P1>
{
public struct Q
{
}
}
}
}
}
}
type = typeof(List<Dictionary<string[], C.D<byte, short[,]>.E.K<List<int>[,][], Action<List<long[][][,]>[], double[][,]>, float>.P<string>.Q>>[][,][,,,][][,,]);
// Returns "System.Collections.Generic.List<System.Collections.Generic.Dictionary<System.String[],Test.Program.C.D<System.Byte,System.Int16[,]>.E.K<System.Collections.Generic.List<System.Int32>[,][],System.Action<System.Collections.Generic.List<System.Int64[][][,]>[],System.Double[][,]>,System.Single>.P<System.String>.Q>>[][,][,,,][][,,]":
GetTypeCSharpRepresentation(type);
There may still be some gotchas I didn't think about, but there's a known one: to retrieve the names, I only get characters that meet the condition char.IsLetterOrDigit(c) || c == '_' until one that doesn't is found, so any names of types that use allowed characters that don't meet the condition will fail.
Came across this and thought I'd share my own solution. It handles multiple generic arguments, nullables, jagged arrays, multidimensional arrays, combinations of jagged/multidimensional arrays, and any nesting combinations of any of the above. I use it mainly for logging so that it's easier to identify complicated types.
public static string GetGoodName(this Type type)
{
var sb = new StringBuilder();
void VisitType(Type inType)
{
if (inType.IsArray)
{
var rankDeclarations = new Queue<string>();
Type elType = inType;
do
{
rankDeclarations.Enqueue($"[{new string(',', elType.GetArrayRank() - 1)}]");
elType = elType.GetElementType();
} while (elType.IsArray);
VisitType(elType);
while (rankDeclarations.Count > 0)
{
sb.Append(rankDeclarations.Dequeue());
}
}
else
{
if (inType.IsGenericType)
{
var isNullable = inType.IsNullable();
var genargs = inType.GetGenericArguments().AsEnumerable();
var numer = genargs.GetEnumerator();
numer.MoveNext();
if (!isNullable) sb.Append($"{inType.Name.Substring(0, inType.Name.IndexOf('`'))}<");
VisitType(numer.Current);
while (numer.MoveNext())
{
sb.Append(",");
VisitType(numer.Current);
}
if (isNullable)
{
sb.Append("?");
}
else
{
sb.Append(">");
}
}
else
{
sb.Append(inType.Name);
}
}
}
VisitType(type);
var s = sb.ToString();
return s;
}
This:
typeof(Dictionary<int?, Tuple<string[], List<string[][,,,]>>>).GetGoodName()
...returns this:
Dictionary<Int32?,Tuple<String[],List<String[][,,,]>>>
If you want the base generic type used:
List<string> lstString = new List<string>();
Type type = lstString.GetType().GetGenericTypeDefinition();
Assuming that you want to use the type do do something and that you don't really need the actual string definition which isn't all that useful.

C# string Parsing to variable types

I want to parse a string into a type easily, but I don't want to write wrapper code for each type, I just want to be able to do "1234".Parse() or the like and have it return 1234. This should work for any type that has parsing capabilities.
This trick should work. It uses the type of the variable you're assigning to automagically:
public static class StringExtensions {
public static ParsedString Parse(this string s) {
return new ParsedString(s);
}
}
public class ParsedString {
string str;
public ParsedString(string s) {
str = s;
}
public static implicit operator int(ParsedString s) {
return int.Parse(s.str);
}
public static implicit operator double(ParsedString s) {
return double.Parse(s.str);
}
public static implicit operator short(ParsedString s) {
return short.Parse(s.str);
}
public static implicit operator byte(ParsedString s) {
return byte.Parse(s.str);
}
// ... add other supported types ...
}
Usage:
int p = "1234".Parse();
I would prefer explicitly parsing using framework provided methods rather than relying on these kind of tricks.
My solution works for any type that implements the static method TryParse(string, out T), whether it's a class or a struct. Also, it will work for nullable structs, e.g.
"1234".Parse<int>() == 1234
"asdf".Parse<int>() == 0 // i.e. default(int)
"1234".Parse<int?>() == 1234
"asdf".Parse<int?>() == null
"2001-02-03".Parse<DateTime?>() == new DateTime(2009, 2, 3)
and since System.Net.IPAddress has TryParse,
"127.0.0.1".Parse<IPAddress>().Equals(new IPAddress(new byte[] { 127, 0, 0, 1 }))
I create the code with the System.Linq.Expressions framework, and then cache the created lambda. Since this is done in a generic static class with a specified type, this happens only once per type to parse.
public static class StringExtensions
{
/// <summary>
/// Parse the <paramref name="target"/> as a <typeparamref name="T"/>. If this cannot be achieved, return the default value of <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type to parse into.</typeparam>
/// <param name="target">The string to parse.</param>
/// <returns>The resultant <typeparamref name="T"/> or the default of <typeparamref name="T"/>.</returns>
/// <example>
/// <code>
/// "1234".Parse&ltint>() == 1234;
/// "a".Parse&ltint>() == 0;
/// "a".Parse&ltint?>() == null;
/// "2010-01-01".Parse<DateTime?>() == new DateTime(2010, 1, 1)
/// "2010-01-01a".Parse<DateTime?>() == null
/// "127.0.0.1".Parse<System.Net.IPAddress>().Equals(new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 }))
/// "".Parse<System.Net.IPAddress>() == null
/// </code>
/// </example>
public static T Parse<T>(this string target)
{
return ParseHelper<T>.Parse(target);
}
/// <summary>
/// Parse the <paramref name="target"/> as a <typeparamref name="T"/>. If this cannot be achieved, return <paramref name="defaultValue"/>
/// </summary>
/// <typeparam name="T">The type to parse into.</typeparam>
/// <param name="target">The string to parse.</param>
/// <param name="defaultValue">The value to return if <paramref name="target"/> could not be parsed.</param>
/// <returns>The resultant <typeparamref name="T"/> or <paramref name="defaultValue"/>.</returns>
/// <example>
/// <code>
/// "1234".Parse&ltint>(-1) == 1234;
/// "a".Parse&ltint>(-1) == -1;
/// "2010-01-01".Parse<DateTime?>(new DateTime(1900, 1, 1)) == new DateTime(2010, 1, 1)
/// "2010-01-01a".Parse<DateTime?>(new DateTime(1900, 1, 1)) == new DateTime(1900, 1, 1)
/// "127.0.0.1".Parse<System.Net.IPAddress>(new System.Net.IPAddress(new byte[] { 0, 0, 0, 0 })).Equals(new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 }))
/// "".Parse<System.Net.IPAddress>(new System.Net.IPAddress(new byte[] { 0, 0, 0, 0 })).Equals(new System.Net.IPAddress(new byte[] { 0, 0, 0, 0 }))
/// </code>
/// </example>
public static T Parse<T>(this string target, T defaultValue)
{
return ParseHelper<T>.Parse(target, defaultValue);
}
private static class ParseHelper<T>
{
private static readonly Func<string, T, T, T> _parser;
static ParseHelper()
{
Type type = typeof(T);
bool isNullable = false;
if (type.GetGenericArguments().Length > 0 && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
isNullable = true;
type = type.GetGenericArguments()[0];
}
ParameterExpression target = Expression.Parameter(typeof(string), "target");
ParameterExpression defaultValue = Expression.Parameter(typeof(T), "defaultValue");
ParameterExpression result = Expression.Parameter(typeof(T), "result");
if (isNullable)
{
Type helper = typeof(NullableParseHelper<>);
helper = helper.MakeGenericType(typeof(T), type);
MethodInfo parseMethod = helper.GetMethod("Parse");
_parser = Expression.Lambda<Func<string, T, T, T>>(
Expression.Call(parseMethod, target, defaultValue),
target, defaultValue, result).Compile();
}
else
{
MethodInfo tryParseMethod = (from m in typeof(T).GetMethods()
where m.Name == "TryParse"
let ps = m.GetParameters()
where ps.Count() == 2
&& ps[0].ParameterType == typeof(string)
&& ps[1].ParameterType == typeof(T).MakeByRefType()
select m).SingleOrDefault();
if (tryParseMethod == null)
{
throw new InvalidOperationException(string.Format("Cannot find method {0}.TryParse(string, out {0})", type.FullName));
}
_parser = Expression.Lambda<Func<string, T, T, T>>(
Expression.Condition(
Expression.Call(tryParseMethod, target, result),
result,
defaultValue),
target, defaultValue, result).Compile();
}
}
public static T Parse(string target)
{
return _parser.Invoke(target, default(T), default(T));
}
public static T Parse(string target, T defaultValue)
{
return _parser.Invoke(target, defaultValue, default(T));
}
private static class NullableParseHelper<TBase> where TBase : struct
{
private static readonly Func<string, TBase?, TBase, TBase?> _parser;
static NullableParseHelper()
{
MethodInfo tryParseMethod = (from m in typeof(TBase).GetMethods()
where m.Name == "TryParse"
let ps = m.GetParameters()
where ps.Count() == 2
&& ps[0].ParameterType == typeof(string)
&& ps[1].ParameterType == typeof(TBase).MakeByRefType()
select m).SingleOrDefault();
if (tryParseMethod == null)
{
throw new InvalidOperationException(string.Format("Cannot find method {0}.TryParse(string, out {0})", typeof(TBase).FullName));
}
ParameterExpression target = Expression.Parameter(typeof(string), "target");
ParameterExpression defaultValue = Expression.Parameter(typeof(TBase?), "defaultValue");
ParameterExpression result = Expression.Parameter(typeof(TBase), "result");
_parser = Expression.Lambda<Func<string, TBase?, TBase, TBase?>>(
Expression.Condition(
Expression.Call(tryParseMethod, target, result),
Expression.ConvertChecked(result, typeof(TBase?)),
defaultValue),
target, defaultValue, result).Compile();
}
public static TBase? Parse(string target, TBase? defaultValue)
{
return _parser.Invoke(target, defaultValue, default(TBase));
}
}
}
}
pants!
Why can't you use the parsing already available?
int.Parse("1234");
decimal.Parse("1234");
double.Parse("1234");
Or use TryParse if you're not sure it will be able to successfully parse.
Or if you wanted to implement it as an extension method, take a look at this article that will show you how to create a Generic String.Parse method.
Edit: I have no idea how that site went down so quickly after I posted my answer. Here is the class that the article created:
using System;
using System.ComponentModel;
public static class Parser {
public static T Parse<T>(this string value) {
// Get default value for type so if string
// is empty then we can return default value.
T result = default(T);
if (!string.IsNullOrEmpty(value)) {
// we are not going to handle exception here
// if you need SafeParse then you should create
// another method specially for that.
TypeConverter tc = TypeDescriptor.GetConverter(typeof(T));
result = (T)tc.ConvertFrom(value);
}
return result;
}
}
Examples:
// regular parsing
int i = "123".Parse<int>();
int? inull = "123".Parse<int?>();
DateTime d = "01/12/2008".Parse<DateTime>();
DateTime? dn = "01/12/2008".Parse<DateTime?>();
// null values
string sample = null;
int? k = sample.Parse<int?>(); // returns null
int l = sample.Parse<int>(); // returns 0
DateTime dd = sample.Parse<DateTime>(); // returns 01/01/0001
DateTime? ddn = sample.Parse<DateTime?>(); // returns null
I know this question is four years old, but still you could consider using this:
public static T Parse<T>(this string target)
{
Type type = typeof(T);
//In case of a nullable type, use the underlaying type:
var ReturnType = Nullable.GetUnderlyingType(type) ?? type;
try
{
//in case of a nullable type and the input text is null, return the default value (null)
if (ReturnType != type && target == null)
return default(T);
return (T)Convert.ChangeType(target, ReturnType);
}
catch
{
return default(T);
}
}
You can do this with a series of .TryParse() if blocks, but you won't be able to do much with it, since this method will have to return type object. So at the call site, you'll just have to attempt to cast it before doing any arithmetic or anything anyway.
You could write a wrapper function that calls tryParse for each type that you want to support.
There are two problems with that scenario. First you would have to write some code to analyse the string to try to determine what data types it would be possible to parse into, and then some logic to choose one of them. (The string "1" for example would be parsable to byte, sbyte, int, uint, long, ulong, float, double and Decimal. Even worse, the string "4.8.12" would be parsable to several numeric types as well as DateTime in three different ways resulting in totally different values...)
The other problem is that any method capable of doing that would have to return the value boxed in an object, so you would still need wrapper code for each data type just to unbox the value.
Besides, what would you do with a value where you have no control over the type? So, don't try to make this simpler, it only gets a lot more complicated.

Can my enums have friendly names? [duplicate]

This question already has answers here:
Associating enums with strings in C#
(38 answers)
Closed 9 years ago.
I have the following enum
public enum myEnum
{
ThisNameWorks,
This Name doesn't work
Neither.does.this;
}
Is it not possible to have enums with "friendly names"?
You could use the Description attribute, as Yuriy suggested. The following extension method makes it easy to get the description for a given value of the enum:
public static string GetDescription(this Enum value)
{
Type type = value.GetType();
string name = Enum.GetName(type, value);
if (name != null)
{
FieldInfo field = type.GetField(name);
if (field != null)
{
DescriptionAttribute attr =
Attribute.GetCustomAttribute(field,
typeof(DescriptionAttribute)) as DescriptionAttribute;
if (attr != null)
{
return attr.Description;
}
}
}
return null;
}
You can use it like this:
public enum MyEnum
{
[Description("Description for Foo")]
Foo,
[Description("Description for Bar")]
Bar
}
MyEnum x = MyEnum.Foo;
string description = x.GetDescription();
Enum value names must follow the same naming rules as all identifiers in C#, therefore only first name is correct.
If you have the following enum:
public enum MyEnum {
First,
Second,
Third
}
You can declare Extension Methods for MyEnum (like you can for any other type). I just whipped this up:
namespace Extension {
public static class ExtensionMethods {
public static string EnumValue(this MyEnum e) {
switch (e) {
case MyEnum.First:
return "First Friendly Value";
case MyEnum.Second:
return "Second Friendly Value";
case MyEnum.Third:
return "Third Friendly Value";
}
return "Horrible Failure!!";
}
}
}
With this Extension Method, the following is now legal:
Console.WriteLine(MyEnum.First.EnumValue());
Hope this helps!!
No, but you can use the DescriptionAttribute to accomplish what you're looking for.
You can use the Description attribute to get that friendly name. You can use the code below:
public static string ToStringEnums(Enum en)
{
Type type = en.GetType();
MemberInfo[] memInfo = type.GetMember(en.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length > 0)
return ((DescriptionAttribute)attrs[0]).Description;
}
return en.ToString();
}
An example of when you would want to use this method: When your enum value is EncryptionProviderType and you want enumVar.Tostring() to return "Encryption Provider Type".
Prerequisite: All enum members should be applied with the attribute [Description("String to be returned by Tostring()")].
Example enum:
enum ExampleEnum
{
[Description("One is one")]
ValueOne = 1,
[Description("Two is two")]
ValueTow = 2
}
And in your class, you would use it like this:
ExampleEnum enumVar = ExampleEnum.ValueOne;
Console.WriteLine(ToStringEnums(enumVar));
One problem with this trick is that description attribute cannot be localized. I do like a technique by Sacha Barber where he creates his own version of Description attribute which would pick up values from the corresponding resource manager.
http://www.codeproject.com/KB/WPF/FriendlyEnums.aspx
Although the article is around a problem that's generally faced by WPF developers when binding to enums, you can jump directly to the part where he creates the LocalizableDescriptionAttribute.
Some great solutions have already been posted. When I encountered this problem, I wanted to go both ways: convert an enum into a description, and convert a string matching a description into an enum.
I have two variants, slow and fast. Both convert from enum to string and string to enum. My problem is that I have enums like this, where some elements need attributes and some don't. I don't want to put attributes on elements that don't need them. I have about a hundred of these total currently:
public enum POS
{
CC, // Coordinating conjunction
CD, // Cardinal Number
DT, // Determiner
EX, // Existential there
FW, // Foreign Word
IN, // Preposision or subordinating conjunction
JJ, // Adjective
[System.ComponentModel.Description("WP$")]
WPDollar, //$ Possessive wh-pronoun
WRB, // Wh-adverb
[System.ComponentModel.Description("#")]
Hash,
[System.ComponentModel.Description("$")]
Dollar,
[System.ComponentModel.Description("''")]
DoubleTick,
[System.ComponentModel.Description("(")]
LeftParenth,
[System.ComponentModel.Description(")")]
RightParenth,
[System.ComponentModel.Description(",")]
Comma,
[System.ComponentModel.Description(".")]
Period,
[System.ComponentModel.Description(":")]
Colon,
[System.ComponentModel.Description("``")]
DoubleBackTick,
};
The first method for dealing with this is slow, and is based on suggestions I saw here and around the net. It's slow because we are reflecting for every conversion:
using System;
using System.Collections.Generic;
namespace CustomExtensions
{
/// <summary>
/// uses extension methods to convert enums with hypens in their names to underscore and other variants
public static class EnumExtensions
{
/// <summary>
/// Gets the description string, if available. Otherwise returns the name of the enum field
/// LthWrapper.POS.Dollar.GetString() yields "$", an impossible control character for enums
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string GetStringSlow(this Enum value)
{
Type type = value.GetType();
string name = Enum.GetName(type, value);
if (name != null)
{
System.Reflection.FieldInfo field = type.GetField(name);
if (field != null)
{
System.ComponentModel.DescriptionAttribute attr =
Attribute.GetCustomAttribute(field,
typeof(System.ComponentModel.DescriptionAttribute)) as System.ComponentModel.DescriptionAttribute;
if (attr != null)
{
//return the description if we have it
name = attr.Description;
}
}
}
return name;
}
/// <summary>
/// Converts a string to an enum field using the string first; if that fails, tries to find a description
/// attribute that matches.
/// "$".ToEnum<LthWrapper.POS>() yields POS.Dollar
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static T ToEnumSlow<T>(this string value) //, T defaultValue)
{
T theEnum = default(T);
Type enumType = typeof(T);
//check and see if the value is a non attribute value
try
{
theEnum = (T)Enum.Parse(enumType, value);
}
catch (System.ArgumentException e)
{
bool found = false;
foreach (T enumValue in Enum.GetValues(enumType))
{
System.Reflection.FieldInfo field = enumType.GetField(enumValue.ToString());
System.ComponentModel.DescriptionAttribute attr =
Attribute.GetCustomAttribute(field,
typeof(System.ComponentModel.DescriptionAttribute)) as System.ComponentModel.DescriptionAttribute;
if (attr != null && attr.Description.Equals(value))
{
theEnum = enumValue;
found = true;
break;
}
}
if( !found )
throw new ArgumentException("Cannot convert " + value + " to " + enumType.ToString());
}
return theEnum;
}
}
}
The problem with this is that you're doing reflection every time. I haven't measured the performance hit from doing so, but it seems alarming. Worse we are computing these expensive conversions repeatedly, without caching them.
Instead we can use a static constructor to populate some dictionaries with this conversion information, then just look up this information when needed. Apparently static classes (required for extension methods) can have constructors and fields :)
using System;
using System.Collections.Generic;
namespace CustomExtensions
{
/// <summary>
/// uses extension methods to convert enums with hypens in their names to underscore and other variants
/// I'm not sure this is a good idea. While it makes that section of the code much much nicer to maintain, it
/// also incurs a performance hit via reflection. To circumvent this, I've added a dictionary so all the lookup can be done once at
/// load time. It requires that all enums involved in this extension are in this assembly.
/// </summary>
public static class EnumExtensions
{
//To avoid collisions, every Enum type has its own hash table
private static readonly Dictionary<Type, Dictionary<object,string>> enumToStringDictionary = new Dictionary<Type,Dictionary<object,string>>();
private static readonly Dictionary<Type, Dictionary<string, object>> stringToEnumDictionary = new Dictionary<Type, Dictionary<string, object>>();
static EnumExtensions()
{
//let's collect the enums we care about
List<Type> enumTypeList = new List<Type>();
//probe this assembly for all enums
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
Type[] exportedTypes = assembly.GetExportedTypes();
foreach (Type type in exportedTypes)
{
if (type.IsEnum)
enumTypeList.Add(type);
}
//for each enum in our list, populate the appropriate dictionaries
foreach (Type type in enumTypeList)
{
//add dictionaries for this type
EnumExtensions.enumToStringDictionary.Add(type, new Dictionary<object,string>() );
EnumExtensions.stringToEnumDictionary.Add(type, new Dictionary<string,object>() );
Array values = Enum.GetValues(type);
//its ok to manipulate 'value' as object, since when we convert we're given the type to cast to
foreach (object value in values)
{
System.Reflection.FieldInfo fieldInfo = type.GetField(value.ToString());
//check for an attribute
System.ComponentModel.DescriptionAttribute attribute =
Attribute.GetCustomAttribute(fieldInfo,
typeof(System.ComponentModel.DescriptionAttribute)) as System.ComponentModel.DescriptionAttribute;
//populate our dictionaries
if (attribute != null)
{
EnumExtensions.enumToStringDictionary[type].Add(value, attribute.Description);
EnumExtensions.stringToEnumDictionary[type].Add(attribute.Description, value);
}
else
{
EnumExtensions.enumToStringDictionary[type].Add(value, value.ToString());
EnumExtensions.stringToEnumDictionary[type].Add(value.ToString(), value);
}
}
}
}
public static string GetString(this Enum value)
{
Type type = value.GetType();
string aString = EnumExtensions.enumToStringDictionary[type][value];
return aString;
}
public static T ToEnum<T>(this string value)
{
Type type = typeof(T);
T theEnum = (T)EnumExtensions.stringToEnumDictionary[type][value];
return theEnum;
}
}
}
Look how tight the conversion methods are now. The only flaw I can think of is that this requires all the converted enums to be in the current assembly. Also, I only bother with exported enums, but you could change that if you wish.
This is how to call the methods
string x = LthWrapper.POS.Dollar.GetString();
LthWrapper.POS y = "PRP$".ToEnum<LthWrapper.POS>();
public enum myEnum
{
ThisNameWorks,
This_Name_can_be_used_instead,
}
After reading many resources regarding this topic, including StackOverFlow, I find that not all solutions are working properly. Below is our attempt to fix this.
Basically, We take the friendly name of an Enum from a DescriptionAttribute if it exists.
If it does not We use RegEx to determine the words within the Enum name and add spaces.
Next version, we will use another Attribute to flag whether we can/should take the friendly name from a localizable resource file.
Below are the test cases. Please report if you have another test case that do not pass.
public static class EnumHelper
{
public static string ToDescription(Enum value)
{
if (value == null)
{
return string.Empty;
}
if (!Enum.IsDefined(value.GetType(), value))
{
return string.Empty;
}
FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
if (fieldInfo != null)
{
DescriptionAttribute[] attributes =
fieldInfo.GetCustomAttributes(typeof (DescriptionAttribute), false) as DescriptionAttribute[];
if (attributes != null && attributes.Length > 0)
{
return attributes[0].Description;
}
}
return StringHelper.ToFriendlyName(value.ToString());
}
}
public static class StringHelper
{
public static bool IsNullOrWhiteSpace(string value)
{
return value == null || string.IsNullOrEmpty(value.Trim());
}
public static string ToFriendlyName(string value)
{
if (value == null) return string.Empty;
if (value.Trim().Length == 0) return string.Empty;
string result = value;
result = string.Concat(result.Substring(0, 1).ToUpperInvariant(), result.Substring(1, result.Length - 1));
const string pattern = #"([A-Z]+(?![a-z])|\d+|[A-Z][a-z]+|(?![A-Z])[a-z]+)+";
List<string> words = new List<string>();
Match match = Regex.Match(result, pattern);
if (match.Success)
{
Group group = match.Groups[1];
foreach (Capture capture in group.Captures)
{
words.Add(capture.Value);
}
}
return string.Join(" ", words.ToArray());
}
}
[TestMethod]
public void TestFriendlyName()
{
string[][] cases =
{
new string[] {null, string.Empty},
new string[] {string.Empty, string.Empty},
new string[] {" ", string.Empty},
new string[] {"A", "A"},
new string[] {"z", "Z"},
new string[] {"Pascal", "Pascal"},
new string[] {"camel", "Camel"},
new string[] {"PascalCase", "Pascal Case"},
new string[] {"ABCPascal", "ABC Pascal"},
new string[] {"PascalABC", "Pascal ABC"},
new string[] {"Pascal123", "Pascal 123"},
new string[] {"Pascal123ABC", "Pascal 123 ABC"},
new string[] {"PascalABC123", "Pascal ABC 123"},
new string[] {"123Pascal", "123 Pascal"},
new string[] {"123ABCPascal", "123 ABC Pascal"},
new string[] {"ABC123Pascal", "ABC 123 Pascal"},
new string[] {"camelCase", "Camel Case"},
new string[] {"camelABC", "Camel ABC"},
new string[] {"camel123", "Camel 123"},
};
foreach (string[] givens in cases)
{
string input = givens[0];
string expected = givens[1];
string output = StringHelper.ToFriendlyName(input);
Assert.AreEqual(expected, output);
}
}
}
They follow the same naming rules as variable names.
Therefore they should not contain spaces.
Also what you are suggesting would be very bad practice anyway.
Enum names live under the same rules as normal variable names, i.e. no spaces or dots in the middle of the names... I still consider the first one to be rather friendly though...
This is a terrible idea, but it does work.
public enum myEnum
{
ThisNameWorks,
ThisNameDoesntWork149141331,// This Name doesn't work
NeitherDoesThis1849204824// Neither.does.this;
}
class Program
{
private static unsafe void ChangeString(string original, string replacement)
{
if (original.Length < replacement.Length)
throw new ArgumentException();
fixed (char* pDst = original)
fixed (char* pSrc = replacement)
{
// Update the length of the original string
int* lenPtr = (int*)pDst;
lenPtr[-1] = replacement.Length;
// Copy the characters
for (int i = 0; i < replacement.Length; i++)
pDst[i] = pSrc[i];
}
}
public static unsafe void Initialize()
{
ChangeString(myEnum.ThisNameDoesntWork149141331.ToString(), "This Name doesn't work");
ChangeString(myEnum.NeitherDoesThis1849204824.ToString(), "Neither.does.this");
}
static void Main(string[] args)
{
Console.WriteLine(myEnum.ThisNameWorks);
Console.WriteLine(myEnum.ThisNameDoesntWork149141331);
Console.WriteLine(myEnum.NeitherDoesThis1849204824);
Initialize();
Console.WriteLine(myEnum.ThisNameWorks);
Console.WriteLine(myEnum.ThisNameDoesntWork149141331);
Console.WriteLine(myEnum.NeitherDoesThis1849204824);
}
Requirements
Your enum names must have the same number of characters or more than the string that you want to it to be.
Your enum names shouldn't be repeated anywhere, just in case string interning messes things up
Why this is a bad idea (a few reasons)
Your enum names become ugly beause of the requirements
It relies on you calling the initialization method early enough
Unsafe pointers
If the internal format of string changes, e.g. if the length field is moved, you're screwed
If Enum.ToString() is ever changed so that it returns only a copy, you're screwed
Raymond Chen will complain about your use of undocumented features, and how it's your fault that the CLR team couldn't make an optimization to cut run time by 50%, during his next .NET week.
I suppose that you want to show your enum values to the user, therefore, you want them to have some friendly name.
Here's my suggestion:
Use an enum type pattern. Although it takes some effort to implement, it is really worth it.
public class MyEnum
{
public static readonly MyEnum Enum1=new MyEnum("This will work",1);
public static readonly MyEnum Enum2=new MyEnum("This.will.work.either",2);
public static readonly MyEnum[] All=new []{Enum1,Enum2};
private MyEnum(string name,int value)
{
Name=name;
Value=value;
}
public string Name{get;set;}
public int Value{get;set;}
public override string ToString()
{
return Name;
}
}

Categories