Hoodlum
Hoodlum

Reputation: 1503

Problems with IQueryable generic types -- Unable to cast object of type 'System.Xml.Linq.XElement' to type 'X'

I'm trying to build a repository that takes a generic type and returns a generic IQueryable. I have it running when the data source is a db table. I want to do the same thing when the data source is an XML document, but I can't get it to work.

Here's the code:

public IQueryable<T> GetAll()
{
    XElement xml = XElement.Load(this.url);

    IQueryable<T> nodes = null;
    nodes = (
    from c in xml.Nodes().Cast<T>()
    select c).AsQueryable<T>();

    return nodes;
}

Here's the error (which by the way occurs at runtime, not compile):

Unable to cast object of type 'System.Xml.Linq.XElement' to type 'X'

Thanks in advance for your response.

Upvotes: 1

Views: 755

Answers (2)

MarcinJuraszek
MarcinJuraszek

Reputation: 125650

Are you looking for a solution which would automagically translate XML document into your custom class? There is nothing like that.

Possible solutions:

Prepare an interface with conversion method and use that method to convert XElement to your class instances:

public interface IXEntity<T>
{
    T GetEntity(XElement source);
}

public IQueryable<T> GetAll<T>(IXEntityFactory<T> factory)
{
    XElement xml = XElement.Load(this.url);

    var nodes = xml.Elements().Select(xe => factory.GetEntity(xe));
    return nodes.AsQueryable();
}

or extend your method to get conversion delegate:

public IQueryable<T> GetAll<T>(Func<XElement, T> projection)
{
    XElement xml = XElement.Load(this.url);

    var nodes = xml.Elements().Select(xe => projection(xe));
    return nodes.AsQueryable();
}

btw. I have no idea why you're trying to use IQueryable<T>. LINQ to XML uses IEnumerable<T> anyway, so there is no difference between version with AsEnumerable() and without that call.

Upvotes: 1

Reed Copsey
Reed Copsey

Reputation: 564641

You're trying to cast the XElement to T, not it's Value. You should be able to use:

public IQueryable<T> GetAll() where T : IConvertible
{
    XElement xml = XElement.Load(this.url);

    var nodes = xml.Nodes().Select(xe => Convert.ChangeType(xe.Value, typeof(T))).Cast<T>();
    return nodes.AsQueryable();
}

This works by extracting the value as a string, and using Convert to (attempt) to map it to the specified type. This would require the type T to implement IConvertible, so I also added that constraint.

Upvotes: 1

Related Questions