C# - How do I get an anonymous type and then use the same selector to create an object?

296 views Asked by At

So I'm trying out Azure's new DocumentDB. Unfortunately it doesn't allow selectors to a type. It won't let me do:

public IEnumerable<U> GetAll<U>(Expression<Func<T, U>> selector)
{
    return Client.CreateDocumentQuery<T>(Collection.DocumentsLink)
        .Select(selector)
        .AsEnumerable();
}

and use it as:

// Doesn't work
return GetAll(t => new MyViewModel {
    Id = t.Id,
    Name = t.Name,
    Email = t.Email,
    Url = t.Url
});

It says it only supports anonymous types. (I imagine since it's fairly new that will change at some point).

I can solve the problem using a second select:

return GetAll(t => new {
    Id = t.Id,
    Name = t.Name,
    Email = t.Email,
    Url = t.Url
}).Select(t => new MyViewModel() {
    Id = t.Id,
    Name = t.Name,
    Email = t.Email,
    Url = t.Url
}).AsEnumerable();

However that is a pain.

Is there a way to use the same selector twice and just make it anonymous the first time?

1

There are 1 answers

0
Enigmativity On

You'll notice the signature for GetAll contains Expression<Func<T, U>> selector. The Expression part says that this argument is being passed as an expression tree and not as a Func delegate. It's done this way so that the provider can parse the selector and generate the appropriate database calls (often SQL) to fetch your data.

Now, when you use a specific custom type - in your case MyViewModel - the provider hits a problem - it just doesn't know how to convert that type into the database calls. It does know how to translate an anonymous type though.

In then returns an IEnumerable<U> so data returned by GetAll is now in memory so you can then perform the subsequent creation of the MyViewModel type. There's no need to translate to database calls any more.

So the answer is that this is by design. It is very unlikely that this will be a new feature in the future.