当前位置:  开发笔记 > 编程语言 > 正文

我应该如何将字符串转换为C#中的枚举?

如何解决《我应该如何将字符串转换为C#中的枚举?》经验,为你挑选了12个好方法。

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

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

在一个理想的世界里,我可以这样做:

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

但那不是有效的代码.



1> Keith..:

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

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

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

如果您可以访问C#7和最新的.NET,这是最好的方法.

原始答案

在.NET中它相当丑陋(直到4或以上):

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

我倾向于简化这个:

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

然后我可以这样做:

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

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

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

StatusEnum MyStatus = "Active".ToEnum();

最后,如果无法解析字符串,您可能希望使用默认枚举:

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

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

这使得这个电话:

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

但是,我会小心地将这样的扩展方法添加到string(没有命名空间控制)它将出现在所有实例上,string无论它们是否包含枚举(因此1234.ToString().ToEnum(StatusEnum.None)有效但无意义).通常最好避免使用仅在非常特定的上下文中应用的额外方法来混淆Microsoft的核心类,除非您的整个开发团队非常了解这些扩展的作用.


@avinashr对@ McKenzieG1的回答是正确的,但它并不总是重要的.例如,如果您为每个解析进行数据库调用,那么担心枚举解析将是一个毫无意义的微优化.
非常好.你需要在上一个例子中使用where T:struct.
如果性能很重要(通常是)下面的Mckenzieg1给出的答案:http://stackoverflow.com/questions/16100/converting-a-string-to-an-enumeration-value-in-c/38711#38711
Enum.TryParse怎么样?
@HM我不认为扩展在这里是合适的 - 这是一个特殊情况,扩展将适用于_every_ string.如果你真的想这样做,虽然这将是一个微不足道的变化.
在扩展方法定义的末尾需要添加`T:struct,IComparable`。

2> Erwin Mayer..:

使用Enum.TryParse(String, T)(≥.NET4.0):

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

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

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


为区分大小写添加中间布尔参数,这是迄今为止最安全,最优雅的解决方案.
来吧,你们中有多少人从2008年开始实施所选答案,只向下滚动,发现这是更好(现代)的答案.

3> McKenzieG1..:

请注意,Enum.Parse()的性能很糟糕,因为它是通过反射实现的.(对于Enum.ToString也是如此,这是另一种方式.)

如果您需要在性能敏感的代码中将字符串转换为枚举,最好的办法是Enum.Parse()在启动时创建并使用它来进行转换.


哇3ms是可怕的数量级
我已经测量了3ms,在第一次运行时,在桌面计算机上将字符串转换为Enum.(只是为了说明可怕的程度).

4> DavidWhitney..:

你正在寻找Enum.Parse.

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



5> Foyzul Karim..:

您现在可以使用扩展方法:

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

您可以通过以下代码调用它们(这里FilterType是一个枚举类型):

FilterType filterType = type.ToEnum();


@SollyM内部与否,我仍然是维护和使用我的代码的人:如果我在每个intellisense菜单中都有一个ToEnum,就像你说的那样,PI会很恼火,因为你唯一一次转换为枚举是来自字符串或int,你可以肯定你只需要这两种方法.并且两种方法不仅仅是一种,特别是当它们很小并且具有实用类型时:P
@SollyM我会说这是一个可怕的想法因为这个扩展方法将适用于*all*对象类型.两种扩展方法,一种用于字符串,一种用于int,在我看来会更干净,更安全.

6> brendan..:
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);

所以,如果你有一个名为heart的枚举,它将如下所示:

   enum Mood
   {
      Angry,
      Happy,
      Sad
   } 

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



7> Timo..:

谨防:

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

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

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

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

我不想让用户自愿或不情愿地触发这种行为.

另外,正如其他人所提到的,对于大型枚举,性能不太理想,即可能值的数量是线性的.

我建议如下:

    public static bool TryParse(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, EnumCacheExpiration);

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

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


事实上,知道"Enum.(Try)Parse接受多个逗号分隔的参数,并将它们与二进制'或'`组合起来非常有用.意味着您可以将枚举值设置为2的幂,并且您有一种非常简单的方法来解析多个布尔标志,例如."UseSSL,NoRetries,同步".事实上,这可能是它的设计目标.

8> tags2k..:

Enum.Parse是你的朋友:

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



9> Nelly..:

您可以使用默认值扩展接受的答案以避免例外:

public static T ParseEnum(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);


什么时候会抛出异常?

10> gap..:

我们无法假设完全有效的输入,并且随着@ Keith的回答变化:

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



11> Mark Cidade..:
// str.ToEnum()
T static ToEnum(this string str) 
{ 
    return (T) Enum.Parse(typeof(T), str);
}



12> jite.gs..:

将字符串解析为TEnum,不使用try/catch,也不使用.NET 4.5中的TryParse()方法

/// 
/// Parses string to TEnum without try/catch and .NET 4.5 TryParse()
/// 
public static bool TryParseToEnum(string probablyEnumAsString_, out TEnum enumValue_) where TEnum : struct
{
    enumValue_ = (TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0);
    if(!Enum.IsDefined(typeof(TEnum), probablyEnumAsString_))
        return false;

    enumValue_ = (TEnum) Enum.Parse(typeof(TEnum), probablyEnumAsString_);
    return true;
}

推荐阅读
依然-狠幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有