在 C#中将字符串转换为枚举

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

答案

在. NET Core 和. NET> 4 中, 有一个通用的解析方法

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

这也包括 C#7 的新型直列out变量,所以这样做的尝试,解析,转换为明确枚举类型和初始化 + 填充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>();

最后,如果无法解析字符串,则可能需要使用默认的枚举:

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

但是,我会小心地向string添加这样的扩展方法,因为(没有名称空间控制)它将在string所有实例上显示(无论它们是否具有枚举1234.ToString().ToEnum(StatusEnum.None) (因此1234.ToString().ToEnum(StatusEnum.None)1234.ToString().ToEnum(StatusEnum.None)是有效的,但毫无意义)。通常最好避免使用仅适用于非常特定的上下文的额外方法来使 Microsoft 的核心类混乱,除非整个开发团队对这些扩展的工作有很好的了解。

使用Enum.TryParse<T>(String, T)Enum.TryParse<T>(String, T) 4.0):

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

可以使用 C#7.0 的参数类型内联将其进一步简化:

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

请注意, Enum.Parse()的性能Enum.Parse() ,因为它是通过反射实现的。 ( Enum.ToString也是如此, Enum.ToString 。)

如果您需要使用对性能敏感的代码将字符串转换为 Enums,最好的选择是在启动时创建Dictionary<String,YourEnum>并使用它来进行转换。

您正在寻找Enum.Parse

SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");

您现在可以使用扩展方法

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

您可以通过以下代码对其进行调用(此处, FilterType是枚举类型):

FilterType filterType = type.ToEnum<FilterType>();
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);

因此,如果您有一个名为 mood 的枚举,它将看起来像这样:

enum Mood
   {
      Angry,
      Happy,
      Sad
   } 

   // ...
   Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
   Console.WriteLine("My mood is: {0}", m.ToString());

谨防:

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

Enum.(Try)Parse() 接受多个逗号分隔的参数,并将它们与二进制 “或” 组合| 。您不能禁用它,而我认为您几乎从不想要它。

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

即使未定义Threex仍将获得 int 值3 。更糟糕的是:Enum.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.Parse是您的朋友:

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

您可以使用默认值扩展接受的答案,以避免出现异常:

public static T ParseEnum<T>(string value, T defaultValue) where T : struct
{
    try
    {
        T enumValue;
        if (!Enum.TryParse(value, true, out enumValue))
        {
            return defaultValue;
        }
        return enumValue;
    }
    catch (Exception)
    {
        return defaultValue;
    }
}

然后您将其命名为:

StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);

如果默认值不是枚举,则 Enum.TryParse 将失败并引发捕获的异常。

在许多地方在我们的代码中使用此函数多年后,也许最好添加此操作会降低性能的信息!

我们无法假设输入完全正确,因此采用了 @Keith 答案的这种变化形式:

public static TEnum ParseEnum<TEnum>(string value) where TEnum : struct
{
    TEnum tmp; 
    if (!Enum.TryParse<TEnum>(value, true, out tmp))
    {
        tmp = new TEnum();
    }
    return tmp;
}