带有标志属性的 Enum.TryParse

Posted

技术标签:

【中文标题】带有标志属性的 Enum.TryParse【英文标题】:Enum.TryParse with Flags attribute 【发布时间】:2011-02-14 06:39:00 【问题描述】:

我已经按值或按名称将代码写入TryParse 枚举,如下所示。如何扩展此代码以包含解析具有 Flags 属性的枚举?

    public static bool TryParse<T>(this T enum_type, object value, out T result) 
                where T : struct
            
                return enum_type.TryParse<T>(value, true, out result);
            



 public static bool TryParse<T>(this T enum_type, 
object value, bool ignoreCase, out T result)
        where T : struct
    
        result = default(T);
        var is_converted = false;

        var is_valid_value_for_conversion = new Func<T, object, bool, bool>[]
            (e, v, i) => e.GetType().IsEnum,
            (e, v, i) => v != null,
            (e, v, i) => Enum.GetNames(e.GetType()).Any(n => String.Compare(n, v.ToString(), i) == 0) || Enum.IsDefined(e.GetType(), v)
        ;

        if(is_valid_value_for_conversion.All(rule => rule(enum_type, value, ignoreCase)))
            result = (T)Enum.Parse(typeof(T), value.ToString(), ignoreCase);
            is_converted = true;
        

        return is_converted;
    

目前此代码适用于以下枚举:

enum SomeEnum A, B, C  
// can parse either by 'A' or 'a'

enum SomeEnum1 : int  A = 1, B = 2, C = 3  
// can parse either by 'A' or 'a' or 1 or "1"

不适用于:

[Flags]
enum SomeEnum2  A = 1, B = 2, C = 4  // can parse either by 'A' or 'a'
// cannot parse for A|B

谢谢!

【问题讨论】:

【参考方案1】:

从 .NET 4 开始,有一个 Enum.TryParse<T> 方法。它支持 Flags 开箱即用的枚举:

string x = (SomeEnum2.A | SomeEnum2.B).ToString();  //  x == "A, B"
SomeEnum2 y;
bool success = Enum.TryParse<SomeEnum2>(x, out y);  //  y == A|B

【讨论】:

为什么不直接使用 Enum.Parse 并在其周围包裹一个 try/catch 块?【参考方案2】:

标志枚举是使用, 通过使用.Net 约定而不是| 编写的。 Enum.Parse() 在使用 ',' 字符串时效果很好:

[Flags]
public enum Flags

    A = 1,
    B = 2,
    C = 4,
    D = 8,


var enumString =  (Flags.A | Flags.B | Flags.C).ToString();
Console.WriteLine(enumString); // Outputs: A, B, C
Flags f = (Flags)Enum.Parse(typeof(Flags),  enumString);
Console.WriteLine(f); // Outputs: A, B, C

【讨论】:

【参考方案3】:

@Pop 的回答给了我一个线索,我修改了代码中的规则检查,如下所示:

var is_valid_value_for_conversion = new Func<T, object, bool, bool>[]

    (e, v, i) => e.GetType().IsEnum,
    (e, v, i) => value != null,
    (e, v, i) => Enum.GetNames(e.GetType()).Any(
                n => String.Compare(n, v.ToString(), i) == 0 
                || (v.ToString().Contains(",") && v.ToString().ToLower().Contains(n.ToLower()))) 
                || Enum.IsDefined(e.GetType(), v)
;

其余部分保持不变,对我有用

其他人

【讨论】:

空检查不应该是你的第一条规则吗? 第一次检查或第二次检查在这种情况下 IMO 不会有什么不同,除非我遗漏了什么,除了因为约束在结构上,我认为我们需要检查调用是否在有效枚举上在检查值是否为空之前输入

以上是关于带有标志属性的 Enum.TryParse的主要内容,如果未能解决你的问题,请参考以下文章

打开枚举(带有标志属性)而不声明所有可能的组合?

使用带有标志枚举的 ProtoBuf-Net 时出错

使用带有 Core Data 的脏标志与服务器同步

带有“允许同源”标志错误的 iframe 沙盒

带有标志的 Html 国家/地区列表 [关闭]

如何在 Bash 中获取带有标志的参数