我有一个C#模块,用于接收和处理Operation类的各种实例。接口声明了一个方法:
Operation Transform(Operation o1, Operation o2);
但是有几种操作。例如,对于简单的文本编辑,有InsertOperation和DeleteOperation,因此Transform方法的主体首先排序它接收的操作类型并将其转换。在学习了一些F#之后,我想在其中重写项目的这一部分(作为实践和实验)并认为我可以通过这样的模式匹配来更好地处理这个:
let Transform (oa: Operation) (ob: Operation) =
match oa, ob with
| InsertOperation o1, InsertOperation o2 -> //transformation
| DeleteOperation o1, InsertOperation o2 -> //transformation
| InsertOperation o1, DeleteOperation o2 -> //transformation
| DeleteOperation o1, DeleteOperation o2 -> //transformation
但是,我收到以下错误消息:
The pattern discriminator 'InsertOperation' is not defined
Operation类及其后代是用C#编写的,但我认为这不应该造成问题。有人可以解释为什么这是一个问题以及如何解决这个问题?
答案 0 :(得分:7)
由于这不是一个有区别的联合,而只是一组类(用C#编写),你需要使用类型的测试模式:
let Transform (oa: Operation) (ob: Operation) =
match oa, ob with
| (:? InsertOperation as o1), (:? InsertOperation as o2) -> //transformation
| (:? DeleteOperation as o1), (:? InsertOperation as o2) -> //transformation
| (:? InsertOperation as o1), (:? DeleteOperation as o2) -> //transformation
| (:? DeleteOperation as o1), (:? DeleteOperation as o2) -> //transformation
有关详细信息,请参阅Pattern Matching中的类型测试模式。
答案 1 :(得分:4)
另一个答案建议在Transform
函数中对类型进行直接匹配,这是一个很好的解决方案。如果您为自己的案例定义自定义active pattern,则可以考虑一些样板文件,特别是因为它听起来您将不止一次与Operation
类型匹配。
let (|Insert|Delete|Unknown|) (oper: Operation) =
match oper with
| :? InsertOperation as iop -> Insert iop
| :? DeleteOperation as dop -> Delete dop
| _ -> Unknown // catches other subtypes of Operation you don't know about yet.
然后你可以像这样使用它:
let transform (oa: Operation) (ob: Operation) =
match oa, ob with
| Insert oa, Insert ob -> ...
| Delete oa, Insert ob -> ...
...
| Unknown, _ | _, Unknown -> ...
这为您提供了与区分联合几乎相同的语法,但更重要的是,让您将操作视为模式匹配的封闭类型。例如,您将获得有关您未处理的案例的正确警告,而不是通用的“其他子类型”警告。