0

I'm using Dynamic Linq.

I can do the following:

IQueryable<Person>().Select("new(Id as Id, FirstName + Surname as Name");

This creates an IQueryable (not an IQueryable<object>) containing an anonymous type.

But given I have the following class:

public class ListItem
{
    public ListItem()
    {
    }
    public ListItem(int id, string name)
    {
        this.Id = id;
        this.Name = name;
    }

    public int Id { get; set; }
    public string Name { get; set; }
}

I would like to select directly into this type from my IQueryable<Person> by invoking the constructor of ListItem, equivalent to the following:

IQueryable<Person>().Select(p => new ListItem(p.Id, p.FirstName + p.Surname));

I've tried variants such as:

// Illegal - new expects form "new()" - exception "'(' expected"
IQueryable<Person>().Select("new ListItem(Id, FirstName + Surname)");

// this doesn't work, "No property 'ListItem' exists on type 'Person'"
IQueryable<Person>().Select("ListItem(Id, FirstName + Surname)");

// this doesn't work because "[" is not expected
IQueryable<Person>().Select("[MyProject.Utils.ListItem,MyProject]()");

I believe this to be possible from the documentation available here:

Overload resolution for methods, constructors, and indexers uses rules similar to C#. In informal terms, overload resolution will pick the best matching method, constructor, or indexer, or report an ambiguity error if no single best match can be identified.

Note that constructor invocations are not prefixed by new.

Is this possible or have I misunderstood the documentation?

kaitlinsm
  • 135
  • 2
  • 5

1 Answers1

1

I am not sure if constructors are supported in the Select method in Dynamic Linq. Maybe the documentation is saying that this is only supported for predicates, like the expressions that are used in the Where method. I am not sure though.

Anyway, this might be a solution for you:

var result =
    context
        .Customers
        .Select("new(Id as Id, FirstName + Surname as Name")
        .AsEnumerable()
        .Select(x => new ListItem(x.Id, x.Name))
        .ToList();
Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62
  • I have used a similar approach, but since the type of the object in the first `Select` is dynamically generated, you can't refer to `x.Id`. You'd need instead to use something like AutoMapper, e.g. `.Select(x => AutoMapper.Mapper.DynamicMap())`. – kaitlinsm Nov 02 '15 at 10:24
  • The result of `Select(...).AsEnumerable()` is `IEnumerable` which means that you can use `x.Id`. You won't get intellisense, but the code will compile and run correctly. I actually tried this before posting the answer. – Yacoub Massad Nov 02 '15 at 11:32
  • Whoops! I'd forgotten about `dynamic`. Thanks - I think the answer to my question is that you have to do an explicit conversion step, and that dynamic linq doesn't by default support instantiating particular types. – kaitlinsm Nov 02 '15 at 13:54