【问题标题】:How can I test if an enum is defined or not whilst ignoring case?如何在忽略大小写的情况下测试是否定义了枚举?
【发布时间】:2010-07-01 12:52:40
【问题描述】:

以下通用静态方法采用 string 并返回 enum

很好地忽略大小写,因为我将 ignoreCase 参数设置为 true。

不过,我也想测试枚举是否存在,但执行此操作的 enum.IsDefined 方法似乎没有 ignoreCase 参数。 p>

如何测试枚举是否已定义并同时忽略大小写?

using System;

namespace TestEnum2934234
{
    class Program
    {
        static void Main(string[] args)
        {
            LessonStatus lessonStatus = StringHelpers.ConvertStringToEnum<LessonStatus>("prepared");
            ReportStatus reportStatus = StringHelpers.ConvertStringToEnum<ReportStatus>("finished");

            Console.WriteLine(lessonStatus.ToString());
            Console.WriteLine(reportStatus.ToString());
            Console.ReadLine();
        }
    }

    public static class StringHelpers
    {
        public static T ConvertStringToEnum<T>(string text)
        {
            if (Enum.IsDefined(typeof(T), text)) //does not have ignoreCase parameter
                return (T)Enum.Parse(typeof(T), text, true);
            else
                return default(T);
        }
    }

    public enum LessonStatus
    {
        Defined,
        Prepared,
        Practiced,
        Recorded
    }

    public enum ReportStatus
    {
        Draft,
        Revising,
        Finished
    }
}

【问题讨论】:

  • 您可能需要为枚举考虑默认值 None。除了作为目前的良好做法之外,如果您为任何一个枚举传递一个“Foo”字符串,您会从 ConvertStringToEnum 中获得看似有效的值。

标签: c# enums case-sensitive


【解决方案1】:
public enum MyEnum
{
    Bar,
    Foo
}

class Program
{
    static void Main(string[] args)
    {
        var containsFoo = Enum.GetNames(typeof(MyEnum)).Any(x => x.ToLower() == "foo");
        Console.WriteLine(containsFoo);
    }
}

【讨论】:

  • 这是最好的解决方案!
【解决方案2】:

正如其他人所说,您可能只需使用Enum.TryParse 就可以逃脱惩罚。

但是,如果您想要一个更强大/更通用的转换,允许您转换的不仅仅是字符串,那么您还需要使用 Enum.IsDefined,不幸的是,正如您发现的那样,不是不区分大小写。

Enum.TryParse (可以)不区分大小写。但不幸的是,它允许超出范围的整数通过!

所以解决方案是一起使用它们(顺序很重要)。

我写了一个扩展方法来做到这一点。它允许从字符串、int/int? 和任何其他 Enum/Enum? 进行转换。像这样输入:

string value1 = "Value1";
Enum2 enum2 = value1.ParseToEnum<Enum2>();
Debug.Assert(enum2.ToString() == value1);

Enum1 enum1 = Enum1.Value1;
enum2 = enum1.ParseToEnum<Enum2>();
Debug.Assert(enum2.ToString() == enum1.ToString());

int value2 = 1;
enum2 = value2.ParseToEnum<Enum2>();
Debug.Assert(enum2.GetHashCode() == value2);

这是该方法的核心。这是回答您问题的转换部分。变量value 的类型为object,因为“重载”我将不同的类型作为主要输入(见上文),但您可以使用string 类型的变量来执行此操作,如果仅此而已你想要(显然将 value.ToString() 更改为 value)。

if (value != null)
{
    TEnum result;
    if (Enum.TryParse(value.ToString(), true, out result))
    {
        // since an out-of-range int can be cast to TEnum, double-check that result is valid
        if (Enum.IsDefined(typeof(TEnum), result.ToString()))
        {
            return result;
        }
    }
}

我的扩展方法还有很多...它允许您指定默认值,处理超出范围的整数,并且完全不区分大小写。如果有人感兴趣,我可以发布更多。

【讨论】:

  • 对我来说关键是使用 TryParse 的输出 .ToString 的结果的想法;谢谢你。其他只建议 TryParse 的人会错过可能给出误报匹配的超出范围的整数。
【解决方案3】:

随着@Darin 的回答,在 .NET 4.0 中,Enum 类型现在有一个 TryParse 方法:

MyEnum result;
Enum.TryParse("bar", true, out result);

要记住的重要一点是 Parse 与 TryParse 的行为存在根本差异。解析方法会抛出异常。 TryParse 方法不会。这对于了解您是否可能尝试解析许多项目非常重要。

【讨论】:

  • 这可能会返回字符串化数值的意外结果。即Enum.TryParse("01", true, out result) 将返回true,如果碰巧有一个值为1 的枚举。另一方面,达林的答案只会匹配枚举名称。
  • @BenCottrell Enum.TryParse("01", true, out result) 将返回 true,即使枚举中没有 1 的值。人们应该意识到这一点。要获得更强大的解决方案,必须将两者结合使用。
【解决方案4】:

我也有类似的担忧,并结合使用了.Enum.TryPase(不区分大小写的标志设置为true)和Enum.IsDefined。将以下内容视为您的帮助程序类的简化:

public static class StringHelpers
{
    public static T ConvertStringToEnum<T>(string text)
    {
        T result;
        return Enum.TryParse(text, true, out result)
            && Enum.IsDefined(result.ToString())
                ? result
                : default(T);
    }
}

当我们这样做的时候,由于帮助类是静态的并且方法是静态的 - 我们可以在 string 上将其作为扩展方法。

public static class StringExtensions
{
    public static TEnum ToEnum<TEnum>(this string text)
        where TEnum : struct, IComparable, IFormattable, IConvertible 
    {
        TEnum result = default(TEnum);
        return !string.IsNullOrWhiteSpace(text) 
            && Enum.TryParse(text, true, out result)
            && Enum.IsDefined(typeof(TEnum), result.ToString())
                ? result
                : default(TEnum);
    }
}

在这里,我创建了一个.NET Fiddle,清楚地证明了这一点。

【讨论】:

  • 如果您向其传递一个包含未出现在枚举中的整数值的字符串,此方法将失败。使用您的小提琴示例,尝试调用Console.WriteLine("55".ToEnum&lt;ReportStatus&gt;());
【解决方案5】:

使文本与枚举字符串大小写相同:

enum FileExts
{
  jpg,
  pdf
}

if (Enum.IsDefined(typeof(T), text.tolower())) //does not have ignoreCase parameter
    return (T)Enum.Parse(typeof(T), text, true);
else
    return default(T);

【讨论】:

    【解决方案6】:

    首先使用Enum.TryParse方法获取T类型的对象,然后将该对象传递给Enum.IsDefined方法:

    private static T ConvertStringToEnum<T>(string stringValue) where T : struct
    {
        if (System.Enum.TryParse(stringValue, out T result))
        {
            if (System.Enum.IsDefined(typeof(T), result) || result.ToString().Contains(","))
                return result;
    
            throw new System.Exception($"{stringValue} is not an underlying value of the {typeof(T).FullName} enumeration.");
        }
    
        throw new System.Exception($"{stringValue} is not a member of the {typeof(T).FullName} enumeration.");
    }
    

    【讨论】:

    • 除此不忽略大小写。
    【解决方案7】:

    改用Enum.TryParse

    T val;
    
    if(Enum.TryParse(text, true, out val))
        return val;
    else 
        return default(T);
    

    【讨论】:

      【解决方案8】:

      我正在使用 Compact Framework 3.5,并且:

      Enum.TryParse
      

      ...不存在。它确实有:

      Enum.IsDefined
      

      ..但不支持 ignoreCase 参数。 我想要两全其美,所以想出了这个(作为辅助方法)......

      public bool TryParse<TEnum>(string value, bool ignoreCase, ref TEnum result) where TEnum : struct
      {
          bool parsed;
          try
          {
              result = (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase);
              parsed = true;
          }
          catch { }
          return parsed;
      }
      

      HTH

      【讨论】:

      • 如果您向其传递一个包含未出现在枚举中的整数值的字符串,此方法将失败。尝试将“55”解析为System.DayOfWeek 枚举。
      【解决方案9】:
          enum DaysCollection
          {
           sunday,
           Monday,
           Tuesday,
           Wednesday,
           Thursday,
           Friday,
           Saturday
          }
      
          public bool isDefined(string[] arr,object obj)
          {
              bool result=false;
              foreach (string enu in arr)
              {
                    result = string.Compare(enu, obj.ToString(), true) == 0;
                    if (result)
                        break;
      
              }
              return result;
      
      
          }
      
          private void button1_Click(object sender, EventArgs e)
          {
              object obj = "wednesday";
              string[] arr = Enum.GetNames(typeof(DaysCollection)).ToArray();
      
              isDefined(arr,obj);
          }
      

      【讨论】:

        【解决方案10】:
        public static T ConvertStringToEnum<T>(string text)
        {
            T returnVal;
            try
            {
                returnVal = (T) Enum.Parse( typeof(T), text, true );
            }
            catch( ArgumentException )
            {
                returnVal = default(T);
            }
            return returnVal;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-08-05
          • 2011-02-20
          • 1970-01-01
          • 1970-01-01
          • 2011-11-20
          • 1970-01-01
          • 1970-01-01
          • 2016-07-05
          相关资源
          最近更新 更多