8

Sto tentando di creare vari metodo di estensione per un tipo generico legato a specifici parametri di tipo generico in F #, ma la lingua non mi sembrano essere permettendo:metodi di estensione per specifici tipi generici

Quello che ho voglio fare è qualcosa di simile al seguente:

type IEnumerable<int> with 
    member this.foo = 
     this.ToString() 

Eppure mi dà l'errore del compilatore (sottolineando la parola int):

Identificatore imprevisto nel nome del tipo. Operatore infisso previsto, simbolo di quota o altro token.

Il seguente fa lavoro, anche se non specificamente associare il parametro di tipo generico per int, come voglio:

type IEnumerable<'a> with 
    member this.foo = 
     this.ToString() 

Esiste un modo per raggiungere questo obiettivo in F # - sono io forse solo usando la sintassi sbagliata? In caso contrario, sarei grato se qualcuno potesse suggerire una soluzione alternativa, magari usando vincoli di tipo da qualche parte.

risposta

7

questo non è possibile nella versione corrente di F #, purtroppo. Vedi la domanda correlata here.

+0

Sembra che tu abbia ragione. Grazie comunque. – Noldorin

+0

Questa funzionalità è tracciata da un suggerimento nel database di bug F # interno "4548: metodi di estensione del supporto per istanze di tipi specifici" ma è improbabile che sia possibile effettuare il taglio per la versione VS2010. – Brian

0

Bene, è possibile utilizzare i vincoli, ma non con tipi chiusi come int.

type IEnumerable<'a when 'a :> InheritableType> = 
member this.Blah = 
    this.ToString() 

Hmm ...

+1

Grazie per il suggerimento, ma in effetti, sto lavorando con un tipo chiuso qui, quindi non funziona. – Noldorin

+0

Probabilmente questo non fa proprio quello che pensi ... In realtà stai definendo un nuovo tipo 'IEnumerable' - prova a chiamare l'estensione su un' IEnumerable esistente. – kvb

6

metodi di estensione generici sono ora disponibili in F # 3.1:

open System.Runtime.CompilerServices 
open System.Collections.Generic 

[<Extension>] 
type Utils() = 
    [<Extension>] 
    static member inline Abc(obj: IEnumerable<int>) = obj.ToString() 

printfn "%A" ([1..10].Abc()) 
0

Al fine di aiutare gli altri in cerca di soluzioni simili, ecco un esempio che mostra come utilizzare metodi di estensione generici con vincoli di tipo. Nell'esempio seguente, esiste un vincolo di tipo che richiede che l'argomento type passato esponga un costruttore predefinito. Questo viene fatto usando l'attributo [<CLIMutable>] applicato al record Order. Inoltre, sto vincolando il risultato del metodo al tipo passato.

Per utilizzare il metodo di estensione è necessario specificare il tipo che si desidera utilizzare. Nota che sto anche estendendo un'interfaccia generica per il dizionario.

[<Extension>] 
type ExtensionMethds() = 

    [<Extension>] 
    static member inline toObject<'T when 'T: (new: unit -> 'T)> (dic: IDictionary<string,obj>): 'T = 
     let instance = new 'T() 
     // todo: set properties via reflection using the dictionary passed in 
     instance 


[<CLIMutable>] 
type Order = {id: int} 

let usage = 
    let dictionaryWithDataFromDb = dict ["id","1" :> obj] 
    let theOrder = dictionaryWithDataFromDb.toObject<Order>() 
    theOrder