c# - enum用法 - enum菜鸟




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

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

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

在理想的世界中,我可以做这样的事情:

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

但这不是有效的代码。


Enum.Parse是你的朋友:

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

谨防:

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

从.NET 4.5开始,没有try / catch和没有TryParse()方法的情况下,将字符串解析为TEnum

/// <summary>
/// Parses string to TEnum without try/catch and .NET 4.5 TryParse()
/// </summary>
public static bool TryParseToEnum<TEnum>(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;
}

你正在寻找Enum.Parse

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

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

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

最后,如果字符串不能被解析,你可能想要使用默认的枚举:

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)会有效但无意义)。 除非整个开发团队都非常了解这些扩展的功能,否则通常最好避免使用仅适用于特定环境的额外方法混淆微软的核心类。


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

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

您现在可以使用扩展方法

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

我们不能假设完全有效的输入,并且与@ 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;
}

我发现这里没有考虑具有EnumMember值的枚举值的情况。 所以我们走吧:

using System.Runtime.Serialization;

public static TEnum ToEnum<TEnum>(this string value, TEnum defaultValue) where TEnum : struct
{
    if (string.IsNullOrEmpty(value))
    {
        return defaultValue;
    }

    TEnum result;
    var enumType = typeof(TEnum);
    foreach (var enumName in Enum.GetNames(enumType))
    {
        var fieldInfo = enumType.GetField(enumName);
        var enumMemberAttribute = ((EnumMemberAttribute[]) fieldInfo.GetCustomAttributes(typeof(EnumMemberAttribute), true)).FirstOrDefault();
        if (enumMemberAttribute?.Value == value)
        {
            return Enum.TryParse(enumName, true, out result) ? result : defaultValue;
        }
    }

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

那个枚举的例子:

public enum OracleInstanceStatus
{
    Unknown = -1,
    Started = 1,
    Mounted = 2,
    Open = 3,
    [EnumMember(Value = "OPEN MIGRATE")]
    OpenMigrate = 4
}

我喜欢扩展方法解决方案..

namespace System
{
    public static class StringExtensions
    {

        public static bool TryParseAsEnum<T>(this string value, out T output) where T : struct
        {
            T result;

            var isEnum = Enum.TryParse(value, out result);

            output = isEnum ? result : default(T);

            return isEnum;
        }
    }
}

这里下面我的测试执行。

using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
using static System.Console;

private enum Countries
    {
        NorthAmerica,
        Europe,
        Rusia,
        Brasil,
        China,
        Asia,
        Australia
    }

   [TestMethod]
        public void StringExtensions_On_TryParseAsEnum()
        {
            var countryName = "Rusia";

            Countries country;
            var isCountry = countryName.TryParseAsEnum(out country);

            WriteLine(country);

            IsTrue(isCountry);
            AreEqual(Countries.Rusia, country);

            countryName = "Don't exist";

            isCountry = countryName.TryParseAsEnum(out country);

            WriteLine(country);

            IsFalse(isCountry);
            AreEqual(Countries.NorthAmerica, country); // the 1rst one in the enumeration
        }

超级简单的代码使用TryParse:

var value = "Active";

StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
    status = StatusEnum.Unknown;

// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str) 
{ 
    return (T) Enum.Parse(typeof(T), str);
}

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.




enums