处理枚举上的不完全模式匹配 [英] Working around incomplete pattern matching on enums
问题描述
[< RequireQualifiedAccess>]
模块枚举=
允许意外<' ,'b,'c当'a:枚举<'b>> (value:'a):'c = //'
failwithf意外的枚举成员:%A:%Atypeof<'a>值//'
与
匹配值ConsoleSpecialKey.ControlC - > ()
| ConsoleSpecialKey.ControlBreak - > ()
| _ - > enum.unexpected value //没有这个,给出不完全模式匹配警告
我认为这是一个很高的顺序,正是因为枚举是弱的。 ConsoleSpecialKey
是完整枚举的一个很好的例子,其中 ControlC
和 ControlBreak $分别由0和1表示的c $ c>是唯一有意义的值。但是我们有一个问题,你可以将任何整数强制到一个
ConsoleSpecialKey
!中:
let x = ConsoleSpecialKey.Parse(typeof< ConsoleSpecialKey>32):?> ConsoleSpecialKey
所以你提供的模式真的不完整,真的需要处理。
(更不用说像$ 编辑:实际上,@ildjarn指出标志属性来区分完整的和位掩码的枚举,尽管编译器不会阻止您在没有标记此属性的枚举上使用按位操作,再次显示弱点的枚举) System.Reflection.BindingFlags
这样的更复杂的枚举,它们用于位掩码,但不能区分从简单的枚举中输入信息,进一步使图片复杂化
但是,如果您正在使用特定的完整枚举,如 ConsoleSpecialKey
并且写出最后一个不完整的模式匹配的情况,所有的时间是真正的bug你,你可以总是鞭打一个完整的主动模式n:
let(| ControlC | ControlBreak |)value =
与
匹配值| ConsoleSpecialKey.ControlC - > ControlC
| ConsoleSpecialKey.ControlBreak - > ControlBreak
| _ - >枚举预期值
//完成
匹配值与
| ControlC - > ()
| ControlBreak - > ()
然而,这类似于简单地将不完整的模式匹配大小写处理,并且抑制了警告。我认为你目前的解决方案是不错的,只要坚持下去,你会很好。
Are there any creative ways to work around .NET's "weak" enums when pattern matching? I'd like them to function similarly to DUs. Here's how I currently handle it. Any better ideas?
[<RequireQualifiedAccess>]
module Enum =
let unexpected<'a, 'b, 'c when 'a : enum<'b>> (value:'a) : 'c = //'
failwithf "Unexpected enum member: %A: %A" typeof<'a> value //'
match value with
| ConsoleSpecialKey.ControlC -> ()
| ConsoleSpecialKey.ControlBreak -> ()
| _ -> Enum.unexpected value //without this, gives "incomplete pattern matches" warning
I think in general this is a tall order, exactly because enums are "weak". ConsoleSpecialKey
is a good example of a "complete" enum where ControlC
and ControlBreak
, which are represented by 0 and 1 respectively, are the only meaningful values it can take on. But we have a problem, you can coerce any integer into a ConsoleSpecialKey
!:
let x = ConsoleSpecialKey.Parse(typeof<ConsoleSpecialKey>, "32") :?> ConsoleSpecialKey
So the pattern you gave really is incomplete and really does needs to be handled.
(not to mention more complex enums like edit: actually, @ildjarn pointed out that the Flags attribute is used, by convention, to distinguish between complete and bitmask enums, though the compiler won't stop you from using bitwise ops on an enum not marked with this attribute, again revealing the weakens of enums).System.Reflection.BindingFlags
, which are used for bitmasking and yet indistinguishable through type information from simple enums, further complicating the picture
But if you are working with a specific "complete" enum like ConsoleSpecialKey
and writing that last incomplete pattern match case all the time is really bugging you, you can always whip up a complete active pattern:
let (|ControlC|ControlBreak|) value =
match value with
| ConsoleSpecialKey.ControlC -> ControlC
| ConsoleSpecialKey.ControlBreak -> ControlBreak
| _ -> Enum.unexpected value
//complete
match value with
| ControlC -> ()
| ControlBreak -> ()
However that's akin to simply leaving the incomplete pattern match case unhandled and suppressing the warning. I think your current solution is nice and you would be good just to stick with it.
这篇关于处理枚举上的不完全模式匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!