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' 警告。
我有一个 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' 警告。