2010-02-14 7 views
6

Ma question est un peu liée à celui-ci - Functions with generic parameter types - mais je ne peux pas tout à fait savoir comment faire ce que je veux.F #: fonctions de surcharge

Je veux définir un « descendants fonction pour envelopper l'appel à 'descendants' sur les différentes classes C# comme ceci:

let nom des descendants (XDocument: XDocument) = xDocument.Descendants nommer

nous descendants name (xElement: XElement) = xElement.Descendants name

Cette approche ne fonctionne pas car nous avons une définition en double de 'descendants'.

je pensais qu'il serait possible d'utiliser la fonction en ligne et résoudre statiquement les paramètres pour définir la méthode suivante pour le faire à la place:

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

Mais je suis obtenir cette erreur en essayant de le faire :

Recherche sur un objet de type indéterminé sur la base des informations antérieures à ce point de programme. Une annotation de type peut être nécessaire avant ce point de programme pour contraindre le type de l'objet. Cela peut permettre à la recherche d'être résolue.

Existe-t-il un moyen que je peux écrire cette deuxième fonction pour faire ce que je veux?

Répondre

4

Le code ci-dessous se compile (et suggère la syntaxe nécessaire pour appeler les fonctions de contrainte de membre statique).

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

D'une manière générale, je pense que chapeau-types tels que ^x sont peut-être trop utilisé (au moins, à en juger par le nombre de questions à leur sujet à SO). C'est une fonctionnalité puissante, mais elle a été conçue principalement pour résoudre des problèmes avec l'arithmétique générique. Je pense qu'ils peuvent compliquer les programmes F #.

Si vous travaillez seulement avec XDocument et XElement, alors la réponse est assez simple, parce que vous pouvez utiliser XContainer qui est leur classe de base commune et a la méthode 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 

Si vous ne pouvez pas trouver une classe de base commune, vous pouvez bien sûr utiliser le type ^a, mais vous pouvez aussi utiliser la surcharge normale, ce qui est possible en F #, mais ne fonctionne que pour les membres de type d'objet:

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()) 

(Puisque vous avez référencé une question avec une réponse qui montre déjà que la surcharge fonctionne avec les membres, ce n'est probablement pas quelque chose de nouveau pour vous. Mais cela peut être utile aux autres qui trouveront cette question dans le futur).

+0

Ah je ne me suis pas rendu compte que la surcharge ne fonctionnait que pour les membres, évidemment n'a pas lu l'autre poste assez étroitement! Je n'ai pas non plus remarqué qu'ils héritaient tous deux de XContainer donc merci, c'est une bien meilleure solution. –

+0

J'ai essayé la surcharge normale et le compilateur dit qu'il y a 2 membres appelés 'Descendants' avec le même nombre d'arguments –

+0

versions, F # compilateur requis '[]' à utiliser lors de la surcharge, mais je ne suis pas sûr de la version qui a été supprimée ... J'ai simplement essayé un exemple plus simple dans F # RC (deux méthodes , à la fois avec deux arguments) et cela a bien fonctionné (sans 'OverloadID'). –

Questions connexes