f#模式匹配c#类

时间:2015-01-09 17:40:17

标签: c# .net f# pattern-matching

我有一个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#编写的,但我认为这不应该造成问题。有人可以解释为什么这是一个问题以及如何解决这个问题?

2 个答案:

答案 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 -> ...

这为您提供了与区分联合几乎相同的语法,但更重要的是,让您将操作视为模式匹配的封闭类型。例如,您将获得有关您未处理的案例的正确警告,而不是通用的“其他子类型”警告。