2012-11-16 8 views
5

私はすでに.Itemのメソッドを実装した.Netライブラリを持っています。このライブラリを使用するコードで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ある)同じ名前の1つの余分方法を追加したい:

#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を同じタイプのシグネチャでは拡張できないことを意味しますが、ここでは別のタイプのシグネチャを使用します。新しいメソッドを拡張できないのはなぜですか?元Library2.Aクラスでそれを見つけ、

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

コンパイラは.Item(...)方法を探している、と失敗します。

+0

私が奇妙なのは、Intellisenseが3つのオーバーロードをすべて表示していることです。 – Daniel

+0

はい。これは私を混乱させます... –

答えて

0

私は思うが、問題は、拡張メソッドは、以下の(C#の)として実装されているという事実によって引き起こされます任意の拡張メソッドを検索します。 すべて.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/en-us/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