2012-11-16 16 views
5

Ho una libreria .Net che ha già implementato i metodi .Item, ad es.Aggiunta di ulteriori metodi come estensioni di tipo in 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" 

Nel codice che utilizza questa libreria, voglio aggiungere un metodo in più con lo stesso nome (quindi è optional extensions):

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

L'ultima riga del seguente esempio non compila :

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

Il F# doc dice:

I metodi di estensione non possono essere metodi virtuali o astratti. Possono sovraccaricare altri metodi con lo stesso nome, ma il compilatore dà la preferenza ai metodi di non estensione nel caso di una chiamata ambigua.

Ciò significa che non è possibile estendere .ToString/.GetHashCode con la stessa firma di tipo, ma qui utilizzo una diversa firma di tipo. Perché il nuovo metodo non può essere esteso?

+0

Quello che trovo strano è che Intellisense mostra tutti e tre i sovraccarichi. – Daniel

+0

si. questo mi confonde ... –

risposta

0

penso, il problema è causato dal fatto metodi di estensione sono implementati come il seguente (C#):

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

Il compilatore è alla ricerca di .Item(...) metodo, lo trova nella classe originale Library2.A, e fallisce per cercare eventuali metodi di estensione.

Nota che se tutti.Item(...) sovraccarichi sono metodi di estensione, tutto funziona bene:

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

C'è differenza tra l'estensione intrinseca e l'estensione opzionale. Il mio caso è 'opzionale'. –

+0

Sì, le estensioni intrinseche sono compilate nel tipo stesso, proprio come le classi 'partial' in C#. [I membri di estensione facoltativi sono compilati in membri statici per i quali l'istanza dell'oggetto viene passata implicitamente come primo parametro.] (Http://msdn.microsoft.com/en-us/library/dd233211.aspx), e questo potrebbe essere ciò che causa il problema – bytebuster

+0

Vale la pena notare: F # supporta le proprietà di estensione, ma C# no.Quindi non esiste una controparte C# per quello che sta cercando di fare. – Daniel

0

Questo sembra essere un bug nel compilatore. Il metodo di estensione è lì e può essere chiamato quando si astengono dalla bella zucchero sintattico che viene fornito con gli indicizzatori, vale a dire questo funziona:

libreria:

namespace TestLibrary 

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

principale:

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 

Il mio primo l'intuizione era che un indicizzatore non può avere unit come tipo di ritorno, ma che non si è rivelato essere il problema.

0

Strano, ho creato una cosa simile in LinqPad e ha funzionato come previsto.

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