Generic version of Enum.Parse in C#

C#GenericsEnums

C# Problem Overview


I have regularly wondered why C# has not yet implemeted a Generic Enum.Parse

Lets say I have

enum MyEnum
{
   Value1,
   Value2
}

And from an XML file/DB entry I wish to to create an Enum.

MyEnum val = (MyEnum)Enum.Parse(typeof(MyEnum), "value1", true);

Could it not have been implemented as something like

MyEnum cal = Enum.Parse<MyEnum>("value1");

This might seem like a small issue, but it seems like an overlooked one.

Any thoughts?

C# Solutions


Solution 1 - C#

It is already implemented in .NET 4 ;) Take a look here.

MyEnum cal;
if (!Enum.TryParse<MyEnum>("value1", out cal))
   throw new Exception("value1 is not valid member of enumeration MyEnum");

Also the discussion here contains some interesting points.

Solution 2 - C#

And in the desired syntax of the question:

MyEnum cal = Toolkit.Parse<MyEnum>("value1");

Note: Since C# forbids you from adding static extensions, you have to house the function elsewhere. i use a static Toolkit class that contains all these useful bits:

/// <summary>
/// Converts the string representation of the name or numeric value of one or
//  more enumerated constants to an equivalent enumerated object.
/// </summary>
/// <typeparam name="TEnum">An enumeration type.</typeparam>
/// <param name="value">A string containing the name or value to convert.</param>
/// <returns>An object of type TEnum whose value is represented by value</returns>
/// <exception cref="System.ArgumentNullException">enumType or value is null.</exception>
/// <exception cref=" System.ArgumentException"> enumType is not an System.Enum. -or- 
/// value is either an empty string or only contains white space.-or- 
/// value is a name, but not one of the named constants defined for the enumeration.</exception>
/// <exception cref="System.OverflowException">value is outside the range of the underlying type of enumType.</exception>
public static TEnum Parse<TEnum>(String value) where TEnum : struct
{
   return (TEnum)Enum.Parse(typeof(TEnum), value);
}

Solution 3 - C#

Although constraining to System.Enum isn't allowed by C#, it is allowed in .NET and C# can use types or methods with such constraints. See Jon Skeet's Unconstrained Melody library, which includes code that does exactly what you want.

Solution 4 - C#

The generic version of Parse<TEnum>(String) was introduced in .NET Core 2.0. So you can just write:

    class Program
    {
        static void Main(string[] args)
        {            
            var e = Enum.Parse<MyEnum>("Value1");
            Console.WriteLine($"Enum values is: {e}");
        }
    }

    enum MyEnum
    {
        Value1,
        Value2
    }

Just keep in mind this is not in "old" .Net Framework (.NET 4.8 and less) or in any .NET Standard. You need to target .NET Core >= 2 (or .NET >= 5 since Microsoft dropped "Core" naming).

There is generic version of TryParse<TEnum>(String, TEnum) since .NET Framework 4.0. So you can use it like that:

if (Enum.TryParse<MyEnum>("Value2", out var e2))
{
    Console.WriteLine($"Enum values is: {e2}");
}

or create your own helper method like:

public static class EnumUtils
{
    public static TEnum Parse<TEnum>(String value) where TEnum : struct
    {
        return (TEnum)Enum.Parse(typeof(TEnum), value);
    }
}

...
var e3 = EnumUtils.Parse<MyEnum>("Value1");

and of course you can just use non-generic version until you migrate your project to newer .NET ;)

var e4 = (MyEnum)Enum.Parse(typeof(MyEnum), "Value1");

Solution 5 - C#

public class EnumHelper
{
    public static T? TryParse<T>(string text)
        where T: struct
    {
        if (string.IsNullOrEmpty(text))
        {
            return null;
        }

        T r;

        if (Enum.TryParse<T>(text, out r))
        {
            return r;
        }

        return null;
    }
}

Solution 6 - C#

Slightly modified version of @ian-boyd's answer, using an extension method to avoid the need to specify a static class name in the call:

MyEnum cal = "value1".Parse<MyEnum>();

/// <summary>
/// Converts the string representation of the name or numeric value of one or
//  more enumerated constants to an equivalent enumerated object.
/// </summary>
/// <typeparam name="TEnum">An enumeration type.</typeparam>
/// <returns>An object of type TEnum whose value is represented by value</returns>
/// <exception cref="System.ArgumentNullException">enumType or value is null.</exception>
/// <exception cref=" System.ArgumentException"> enumType is not an System.Enum. -or- 
/// value is either an empty string or only contains white space.-or- 
/// value is a name, but not one of the named constants defined for the enumeration.</exception>
/// <exception cref="System.OverflowException">value is outside the range of the underlying type of enumType.</exception>
public static TEnum Parse<TEnum>(this String value) where TEnum : struct
{
   return (TEnum)Enum.Parse(typeof(TEnum), value);
}

Solution 7 - C#

While tweaking a little with some methods, trying to build something similar to the initial proposal:

MyEnum cal = Enum.Parse<MyEnum>("value1");

it seemed to me that this syntax won´t be possible in C#, since the Enum type is treated as non-nullable.

If we call the "Enum.TryParse" method passing a value not corresponding to an item of the enum, the Enum´s default value will be returned in the "out" variable. That´s why we need to test the "Enum.TryParse" result first, since simply calling

MyEnum cal;
Enum.TryParse<MyEnum>("value1", out cal);

and checking "cal" value will not always give a reliable result.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAdriaan StanderView Question on Stackoverflow
Solution 1 - C#Tomas VanaView Answer on Stackoverflow
Solution 2 - C#Ian BoydView Answer on Stackoverflow
Solution 3 - C#kvbView Answer on Stackoverflow
Solution 4 - C#Mariusz PawelskiView Answer on Stackoverflow
Solution 5 - C#user2397863View Answer on Stackoverflow
Solution 6 - C#JimmyView Answer on Stackoverflow
Solution 7 - C#Jose TepedinoView Answer on Stackoverflow