在c#中将字符串转换为枚举值的最佳方法是什么?

我有一个包含枚举值的HTML选择标记。当页面被发布时,我想获取值(将以字符串的形式)并将其转换为相应的枚举值。

在理想的情况下,我可以这样做:

StatusEnum MyStatus = StatusEnum.Parse("Active");

但这不是有效的代码。


当前回答

请注意:

enum Example
{
    One = 1,
    Two = 2,
    Three = 3
}

Enum.(Try)Parse()接受多个逗号分隔的参数,并将它们与二进制'或' | '组合。你不能禁用这个,在我看来,你几乎从来都不想要它。

var x = Enum.Parse("One,Two"); // x is now Three

即使没有定义3,x仍然会得到int值3。更糟糕的是:枚举. parse()可以给你一个甚至没有为枚举定义的值!

我不想经历用户自愿或不情愿触发这种行为的后果。

此外,正如其他人所提到的,对于大型枚举(即可能值的数量呈线性),性能不太理想。

我的建议如下:

    public static bool TryParse<T>(string value, out T result)
        where T : struct
    {
        var cacheKey = "Enum_" + typeof(T).FullName;

        // [Use MemoryCache to retrieve or create&store a dictionary for this enum, permanently or temporarily.
        // [Implementation off-topic.]
        var enumDictionary = CacheHelper.GetCacheItem(cacheKey, CreateEnumDictionary<T>, EnumCacheExpiration);

        return enumDictionary.TryGetValue(value.Trim(), out result);
    }

    private static Dictionary<string, T> CreateEnumDictionary<T>()
    {
        return Enum.GetValues(typeof(T))
            .Cast<T>()
            .ToDictionary(value => value.ToString(), value => value, StringComparer.OrdinalIgnoreCase);
    }

其他回答

你必须使用Enum。解析从Enum中获取对象值,之后你必须将对象值更改为特定的Enum值。转换为enum值可以通过使用Convert.ChangeType来实现。请看下面的代码片段

public T ConvertStringValueToEnum<T>(string valueToParse){
    return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
}

在。net Core和。net Framework≥4.0中,有一个通用的解析方法:

Enum.TryParse("Active", out StatusEnum myStatus);

这也包括c# 7的新内联变量,因此它执行try-parse,转换为显式枚举类型,并初始化+填充myStatus变量。

如果你能使用c# 7和最新的。net,这是最好的方法。

原来的答案

在。net中,它相当丑陋(直到4或以上):

StatusEnum MyStatus = (StatusEnum) Enum.Parse(typeof(StatusEnum), "Active", true);

我倾向于将其简化为:

public static T ParseEnum<T>(string value)
{
    return (T) Enum.Parse(typeof(T), value, true);
}

然后我可以这样做:

StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active");

评论中建议的一个选项是添加一个扩展,这很简单:

public static T ToEnum<T>(this string value)
{
    return (T) Enum.Parse(typeof(T), value, true);
}

StatusEnum MyStatus = "Active".ToEnum<StatusEnum>();

最后,如果字符串不能被解析,你可能想要使用一个默认enum:

public static T ToEnum<T>(this string value, T defaultValue) 
{
    if (string.IsNullOrEmpty(value))
    {
        return defaultValue;
    }

    T result;
    return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}

这就要求:

StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);

然而,我会小心地添加这样的扩展方法到字符串(没有命名空间控制),它将出现在字符串的所有实例上,无论它们是否持有enum(因此1234.ToString(). toenum (statusenume . none)将是有效的,但毫无意义)。通常最好避免用只应用于非常特定的上下文的额外方法来混淆微软的核心类,除非您的整个开发团队都非常了解这些扩展的作用。

我开始使用这种方法。性能似乎还可以,但它需要一些样板代码设置。

public enum StatusType {
    Success,
    Pending,
    Rejected
}

static class StatusTypeMethods {

    public static StatusType GetEnum(string type) {
        switch (type) {
            case nameof(StatusType.Success): return StatusType.Success;
            case nameof(StatusType.Pending): return StatusType.Pending;
            case nameof(StatusType.Rejected): return StatusType.Rejected;
            default:
                throw new ArgumentOutOfRangeException(nameof(type), type, null);
        };
    }
}

之后,你可以这样使用它:

StatusType = StatusType.GetEnum("Success");
public static T ParseEnum<T>(string value)            //function declaration  
{
    return (T) Enum.Parse(typeof(T), value);
}

Importance imp = EnumUtil.ParseEnum<Importance>("Active");   //function call

==================== 一个完整的程序 ====================

using System;

class Program
{
    enum PetType
    {
    None,
    Cat = 1,
    Dog = 2
    }

    static void Main()
    {

    // Possible user input:
    string value = "Dog";

    // Try to convert the string to an enum:
    PetType pet = (PetType)Enum.Parse(typeof(PetType), value);

    // See if the conversion succeeded:
    if (pet == PetType.Dog)
    {
        Console.WriteLine("Equals dog.");
    }
    }
}
-------------
Output

Equals dog.

对于性能,这可能会有所帮助:

    private static Dictionary<Type, Dictionary<string, object>> dicEnum = new Dictionary<Type, Dictionary<string, object>>();
    public static T ToEnum<T>(this string value, T defaultValue)
    {
        var t = typeof(T);
        Dictionary<string, object> dic;
        if (!dicEnum.ContainsKey(t))
        {
            dic = new Dictionary<string, object>();
            dicEnum.Add(t, dic);
            foreach (var en in Enum.GetValues(t))
                dic.Add(en.ToString(), en);
        }
        else
            dic = dicEnum[t];
        if (!dic.ContainsKey(value))
            return defaultValue;
        else
            return (T)dic[value];
    }