2010-02-14 11 views
6

Mi pregunta está relacionada de alguna manera con esta - Functions with generic parameter types - pero no puedo entender cómo hacer lo que quiero.F #: funciones de sobrecarga

quiero definir un 'descendientes funcionan para envolver la llamada a 'Los descendientes' en diversas clases de C#, así:

vamos descendientes nombre (XDocument: XDocument) = xDocument.Descendants nombrar

vamos descendientes name (xElement: XElement) = xElement.Descendants name

Este enfoque no funciona porque tenemos una definición duplicada de 'descendientes'.

pensé que sería posible hacer uso de la función en línea y de forma estática resolver los parámetros para definir el siguiente método para hacer esto en su lugar:

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

Pero estoy recibiendo este error al intentar hacer eso :

Búsqueda en el objeto de tipo indeterminado según la información anterior a este punto del programa. Es posible que se necesite una anotación tipo antes de este punto del programa para restringir el tipo del objeto. Esto puede permitir que la búsqueda se resuelva.

¿Hay alguna forma de que pueda escribir esa segunda función para hacer lo que quiero?

Respuesta

4

El código siguiente compila (y sugiere la sintaxis necesaria para llamar a las funciones de restricción de miembros estáticos).

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

En general, creo que los cascos o tipos, tales como ^x están siendo utilizados tal vez demasiado (al menos, a juzgar por el número de preguntas acerca de ellos en SO). Es una característica poderosa, pero realmente fue diseñada principalmente para resolver problemas con aritmética genérica. Creo que pueden hacer que los programas de F # sean innecesariamente complicados.

Si está trabajando solo con XDocument y XElement, entonces la respuesta es bastante simple, ya que se puede utilizar XContainer que es su clase base común y tiene la Descendants método:

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 no puede encontrar una clase base común, entonces por supuesto puede utilizar ^a tipo, pero también se podría utilizar la sobrecarga normal, lo que es posible en C#, pero sólo funciona para elementos del tipo de objeto:

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

(Ya que hizo referencia a una pregunta con una respuesta que ya muestra que la sobrecarga funciona con los miembros, probablemente no sea algo nuevo para usted). Pero puede ser útil para otros que encontrarán esta pregunta en el futuro).

+0

¡Ah, no me di cuenta de que la sobrecarga solo funcionaba para los miembros en realidad, obviamente no leí la otra publicación lo suficiente! Tampoco entendí que ambos heredaron de XContainer así que gracias, esa es una solución mucho mejor. –

+0

Probé la sobrecarga normal en realidad y el compilador dice que hay 2 miembros llamados 'Descendientes' con el mismo número de argumentos –

+0

En algún momento anterior versiones, el compilador F # requirió '[]' para usar cuando se sobrecarga, pero no estoy seguro de en qué versión esto fue eliminado ... Intenté con un ejemplo más simple en F # RC (dos métodos , ambos con dos argumentos) y funcionó bien (sin 'OverloadID'). –

Cuestiones relacionadas