c# 上的 f# 模式匹配 类

f# pattern match on c# classes

我有一个 C# 模块可以接收和处理操作的各种实例 class。该接口声明了一个方法:

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

操作 class 及其后代是用 C# 编写的,但我认为这不应该成为问题。有人可以解释为什么这是一个问题以及我如何解决这个问题吗?

因为这不是一个有区别的联合,而只是一组 类(用 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 中的类型测试模式。

另一个答案建议直接匹配 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 -> ...

这为您提供了与可区分联合几乎相同的语法,但更重要的是,让您可以将您的操作视为用于模式匹配目的的封闭类型。例如,您会收到有关您未处理的案例的适当警告,而不是通用的 'other subtype' 警告。