2012-11-16 30 views
5

我有一個.Net庫,已經實現了.Item方法,例如。在F#中添加額外的方法作爲類型擴展名。

namespace Library2 
type A() = 
    member m.Item with get(a: string) = printfn "get a string" 
    member m.Item with get(a: int) = printfn "simple slice" 

在使用這個庫中的代碼,我想補充的同名一個額外的方法(因此它是optional extensions):

#r @"Library2.dll" 
open Library2 
type A with 
    member m.Item with get(a: bool) = 
     printfn "get a bool" 

下面的示例中的最後一行不編譯:

let a = new A() 
a.["good"]  
a.[10] 
a.[true] 

F# doc說:

擴展方法不能是虛擬或抽象方法。它們可以重載同名的其他方法,但編譯器在非模糊調用的情況下會給非擴展方法優先 。

這意味着我不能使用相同的類型簽名來擴展.ToString/.GetHashCode,但在這裏我使用了不同類型的簽名。爲什麼新方法不能擴展?

+0

我覺得奇怪的是,Intellisense顯示了所有三種重載。 – Daniel

+0

是的。這使我困惑...... –

回答

0

我認爲,這個問題是由事實擴展方法,如下(C#)實現的原因造成的:

public static class MyModule 
{ 
    public static void Item(this A a, bool b) 
    { 
     // whatever 
    } 
} 

編譯器正在尋找.Item(...)方法,發現它在原有Library2.A類,並且失敗搜索任何擴展方法。

注意,如果所有.Item(...)重載是擴展方法,一切工作正常:

module Library2 = 
    type A() = 
     member m.dummy =() 

open Library2 
type A with 
    member m.Item with get(a: string) = printfn "get a string" 
    member m.Item with get(a: int) = printfn "simple slice" 
    member m.Item with get(a: bool) = printfn "get a bool" 
+0

內在擴展和可選擴展之間有區別。我的情況是'可選'。 –

+0

是的,內部擴展被編譯到類型本身中,就像C#中的「partial」類一樣。 [可選擴展成員被編譯爲靜態成員,對象實例作爲第一個參數隱式傳遞。](http://msdn.microsoft.com/zh-cn/library/dd233211.aspx),這可能是什麼導致問題。 – bytebuster

+0

值得注意的是:F#支持擴展屬性,但C#不支持。所以沒有C#對應於他想要做的事情。 – Daniel

0

這似乎是在編譯器中的錯誤。擴展方法是存在的,當你從自帶的索引漂亮的語法糖棄權可以調用,即這個工程:

庫:

namespace TestLibrary 

type A() = 
    member m.Item with get(a: string) = "string" 
    member m.Item with get(a: int) = "int" 

主營:

open TestLibrary 

type A with 
    member m.Item with get(a: bool) = "bool" 

[<EntryPoint>] 
let main argv = 
    let a = new A() 
    printfn "%s" (a.get_Item "a") 
    printfn "%s" (a.get_Item 1) 
    printfn "%s" (a.get_Item true) 
    System.Console.ReadLine() |> ignore 
    0 

我的第一個直覺是索引器不能有unit作爲返回類型,但這並不是問題所在。

0

奇怪的是,我在LinqPad中創建了一個類似的東西,它按照你的預期工作。

module ModuleA = 

    type A() = 
     member m.Item with get(a: string) = printfn "get a string" 
     member m.Item with get(a: int) = printfn "simple slice" 

module ModuleB = 
    open ModuleA 

    type A with 
     member m.Item with get(a: bool) = printfn "get a bool" 

open ModuleB 

let a = new ModuleA.A() 
a.["good"]  
a.[10] 
a.[true] 

// get a string 
// simple slice 
// get a bool