2015-01-09 196 views
3

我有一個C#模塊,它接收和處理Operation類的各種實例。該接口聲明一種方法:c#類上的f#模式匹配

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#編寫,但我認爲這應該不會造成問題。有人可以解釋爲什麼這是一個問題,我怎麼能解決這個問題?

回答

6

因爲這不是一個可識別的聯合,而只是一組類(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中鍵入測試模式。

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

這使您幾乎相同的語法,你就會有一個可識別的聯合,但更重要的是,讓你想想您的操作就好像它是用於模式匹配的封閉類型一樣。例如,您將得到有關您未處理的案例的適當警告,而不是通用的「其他子類型」警告。

+0

哇,這真的很整齊 – Peter