2010-02-14 19 views
6

La mia domanda è in qualche modo correlata a questo - Functions with generic parameter types - ma non riesco a capire come fare ciò che voglio.F #: funzioni di sovraccarico

voglio definire un 'discendenti funzione per avvolgere la chiamata a 'discendenti' su varie classi C# in questo modo:

diamo nome discendenti (XDocument: XDocument) = xDocument.Descendants citarne

lasciare discendenti name (xElement: XElement) = xElement.Descendants name

Questo approccio non funziona perché abbiamo una definizione duplicata di "discendenti".

ho pensato che sarebbe stato possibile fare uso della funzione inline e staticamente risolvere i parametri per definire il seguente metodo per fare questo, invece:

let inline descendants name (xml : ^x when ^x : (member Descendants : XName -> seq<XElement>)) = 
    xml.Descendants name 

Ma sto ottenendo questo errore quando si cerca di farlo :

Ricerca su oggetto di tipo indeterminato basato su informazioni precedenti a questo punto programma. Potrebbe essere necessaria un'annotazione di tipo prima di questo punto del programma per vincolare il tipo dell'oggetto. Ciò potrebbe consentire la risoluzione della ricerca.

C'è un modo in cui posso scrivere quella seconda funzione per fare ciò che voglio?

risposta

4

Il codice sotto compila (ed è indicativo della sintassi necessaria per chiamare le funzioni di vincolo dei membri statici).

open System.Xml.Linq 

let descendants1 name (xDocument:XDocument) = xDocument.Descendants name 

let descendants2 name (xElement:XElement) = xElement.Descendants name 

let inline descendants name (xml : ^x when ^x : (member Descendants : XName -> seq<XElement>)) = 
    (^x : (member Descendants : XName -> seq<XElement>) (xml,name)) 

let xd = XDocument.Load("http://www.somexml.com") 
let ds = descendants (XName.op_Implicit "foo") xd 
let xe = XElement.Load("http://www.somexml.com") 
let eds = descendants (XName.op_Implicit "foo") xe 
14

In generale, penso che hat-tipi come ^x vengono utilizzati forse troppo (almeno, a giudicare dal numero di domande su di loro a SO). È una funzionalità potente, ma è stata progettata principalmente per risolvere problemi con aritmetica generica. Penso che possano rendere i programmi F # inutilmente complicati.

Se si lavora solo con XDocument e XElement, allora la risposta è abbastanza semplice, perché è possibile utilizzare XContainer che è la loro classe base comune e ha il metodo Descendants:

let descendants name (xml:XContainer) = xml.Descendants(name) 

// Both of these will work fine 
descendants (XName.Get "foo") xd 
descendants (XName.Get "foo") xe 

Se non si riesce a trovare una classe base comune, allora si può naturalmente utilizzare ^a tipo, ma si potrebbe anche usare sovraccarico normale, che è possibile in F #, ma funziona solo per i membri oggetto di tipo:

type Xml = 
    static member Descendants(name, x:XDocument) = x.Descendants(name) 
    static member Descendants(name, x:SomeOtherClass) = x.SomeOtherDescendants(name) 

// The usage looks like this: 
Xml.Descendants(XName.Get "foo", xd) 
Xml.Descendants(XName.Get "foo", new SomeOtherClass()) 

(Dato che hai fatto riferimento a una domanda con una risposta che mostra già che il sovraccarico funziona con i membri, questo probabilmente non è nulla di nuovo per te. Ma potrebbe essere utile per gli altri che troveranno questa domanda in futuro).

+0

Ah Non mi sono reso conto che l'overloading ha funzionato solo per i membri in realtà, ovviamente non ho letto l'altro post abbastanza da vicino! Inoltre non ho capito che entrambi hanno ereditato da XContainer quindi grazie, è una soluzione molto migliore –

+0

Ho provato il normale sovraccarico e il compilatore dice che ci sono 2 membri chiamati "Discendenti" con lo stesso numero di argomenti –

+0

In alcuni precedenti versioni, compilatore F # richiesto '[]' da utilizzare durante il sovraccarico, ma non sono sicuro di quale versione sia stata rimossa anche se ... Ho appena provato un esempio più semplice in F # RC (due metodi , entrambi con due argomenti) e ha funzionato correttamente (senza 'OverloadID'). –

Problemi correlati