开发者

Generic version of Enum.Parse in C#

开发者 https://www.devze.com 2022-12-20 02:16 出处:网络
I have regularly wondered why C# has not yet implemeted a Generic Enum.Parse Lets say I have enum MyEnum

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?


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.


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);
}


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.


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");


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;
    }
}


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);
}


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消