代码之家  ›  专栏  ›  技术社区  ›  Ben Mills

如何将字符串转换为C中的枚举?

  •  649
  • Ben Mills  · 技术社区  · 18 年前

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

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

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

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

    但这不是一个有效的代码。

    20 回复  |  直到 8 年前
        1
  •  1098
  •   Keith    9 年前

    在.NET核心和.NET中>4 there is a generic parse method :

    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<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 作为(不带命名空间控件)它将出现在 一串 它们是否持有枚举(因此 1234.ToString().ToEnum(StatusEnum.None) 是有效的,但毫无意义)。通常最好避免用只在非常特定的环境中应用的额外方法来混乱微软的核心类,除非你的整个开发团队对这些扩展有很好的理解。

        2
  •  267
  •   Erwin Mayer    9 年前

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

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

    使用C 7.0可以进一步简化 parameter type inlining :

    Enum.TryParse("Active", out StatusEnum myStatus);
    
        3
  •  170
  •   McKenzieG1    18 年前

    请注意,enum.parse()的性能很糟糕,因为它是通过反射实现的。(Enum.ToString也是如此,反过来也是如此。)

    如果需要在性能敏感的代码中将字符串转换为枚举,最好的办法是创建一个 Dictionary<String,YourEnum> 在启动时使用它进行转换。

        4
  •  77
  •   Peter Mortensen Pieter Jan Bonestroo    11 年前

    你在找 Enum.Parse .

    SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
    
        5
  •  26
  •   Peter Mortensen Pieter Jan Bonestroo    11 年前

    你可以使用 extension methods 现在:

    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>();
    
        6
  •  16
  •   brendan    18 年前
    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());
        7
  •  15
  •   Timo    10 年前

    当心:

    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);
        }
    
        8
  •  13
  •   Peter Mortensen Pieter Jan Bonestroo    11 年前

    Enum.Parse 是你的朋友:

    StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
    
        9
  •  12
  •   Peter Mortensen Pieter Jan Bonestroo    11 年前

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

    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);
    
        10
  •  9
  •   gap    14 年前

    我们不能假设输入是完全有效的,并使用了@keith's答案的这种变体:

    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;
    }
    
        11
  •  7
  •   Mark Cidade    12 年前
    // str.ToEnum<EnumType>()
    T static ToEnum<T>(this string str) 
    { 
        return (T) Enum.Parse(typeof(T), str);
    }
    
        12
  •  5
  •   jite.gs    12 年前

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

    /// <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;
    }
    
        13
  •  3
  •   Brian Rice    9 年前

    使用胰蛋白酶的超简单代码:

    var value = "Active";
    
    StatusEnum status;
    if (!Enum.TryParse<StatusEnum>(value, out status))
        status = StatusEnum.Unknown;
    
        14
  •  2
  •   alhpe    11 年前

    我喜欢扩展方法的解决方案。

    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
            }
    
        15
  •  1
  •   Rae Lee    11 年前
    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.
    
        16
  •  1
  •   Peter Mortensen Pieter Jan Bonestroo    11 年前

    我使用了类(具有解析和性能改进的强类型枚举版本)。我在Github上找到的,它也应该适用于.NET 3.5。它有一些内存开销,因为它缓冲字典。

    StatusEnum MyStatus = Enum<StatusEnum>.Parse("Active");
    

    博客是 Enums – Better syntax, improved performance and TryParse in NET 3.5 .

    代码: https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs

        17
  •  1
  •   Koray    10 年前

    对于性能而言,这可能有助于:

        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];
        }
    
        18
  •  1
  •   isxaker    10 年前

    我发现这里不考虑枚举值为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
    }
    
        19
  •  1
  •   Bartosz Gawron    9 年前

    必须使用Enum.Parse从Enum中获取对象值,然后必须将对象值更改为特定的Enum值。可以使用convert.changeType来强制转换为枚举值。请看下面的代码段

    public T ConvertStringValueToEnum<T>(string valueToParse){
        return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
    }
    
        20
  •  1
  •   user229044    8 年前

    尝试此示例:

     public static T GetEnum<T>(string model)
        {
            var newModel = GetStringForEnum(model);
    
            if (!Enum.IsDefined(typeof(T), newModel))
            {
                return (T)Enum.Parse(typeof(T), "None", true);
            }
    
            return (T)Enum.Parse(typeof(T), newModel.Result, true);
        }
    
        private static Task<string> GetStringForEnum(string model)
        {
            return Task.Run(() =>
            {
                Regex rgx = new Regex("[^a-zA-Z0-9 -]");
                var nonAlphanumericData = rgx.Matches(model);
                if (nonAlphanumericData.Count < 1)
                {
                    return model;
                }
                foreach (var item in nonAlphanumericData)
                {
                    model = model.Replace((string)item, "");
                }
                return model;
            });
        }
    

    在这个示例中,您可以发送每个字符串,并设置 Enum . 如果你 枚举 有你想要的数据,作为你的 枚举 类型。