Syntax to refer a method returning an Expression to another method?
Asked Answered
D

2

6

I found a piece of code of the following form:

public static Expression<Func<Invoice, CustomerContact>> GetCustomerContact()
{
   return i => new CustomerContact {
                 FirstName = i.Customer.FirstName,
                 LastName = i.Customer.LastName,
                 Email = i.Customer.Email,
                 TelMobile = i.Customer.TelMobile,
               };
}

In other parts of the code, I want to get the same lightweight CustomerContact object, only not from the Invoice, but from the Customer itself. So the obvious thing to do would be to have:

public static Expression<Func<Customer, CustomerContact>> GetCustomerContact()
{
   return c => new CustomerContact {
                 FirstName = c.FirstName,
                 LastName = c.LastName,
                 Email = c.Email,
                 TelMobile = c.TelMobile,
               };
}

and then change the Expression taking Invoice as input to refer to this method, i.e. something like this:

public static Expression<Func<Invoice, CustomerContact>> GetCustomerContact()
{
   return i => GetCustomerContact(i.Customer); // doesn't compile
}

What's the correct syntax for this?

Dislike answered 2/6, 2013 at 8:56 Comment(2)
It'd be helpful if you posted the error.Gratian
@newStackExchangeInstance: "Method, delegate or event is expected"Dislike
R
3

You can use Expression.Invoke:

var paramExpr = Expression.Parameter(typeof(Invoice), "i");
var propertyEx = Expression.Property(paramExpr, "Customer");

var body = Expression.Invoke(GetCustomerContactFromCustomer(), propertyEx);

return Expression.Lambda<Func<Invoice, CustomerContact>>(body, paramExpr);

Do note that some LINQ providers have problems with such invocation-expressions.

The easiest way to work around this (and to give you more convenient syntax) is to use LINQKit:

var expr = GetCustomerContactFromCustomer();   
Expression<Func<Invoice, CustomerContact>> result = i => expr.Invoke(i.Customer);    
return result.Expand();
Rebroadcast answered 2/6, 2013 at 9:9 Comment(3)
Ouch, that's quite inelegant. Maybe that is the best solution, but I was hoping there would be a simpler solution that doesn't involve either reflection or third party extensions...Dislike
I don't think there's any way easier than Expression.Invoke to compose expressions in this manner. The LINQKIt way though is quite simple and elegant and gives you back the ability to use language lambdas for this.Rebroadcast
Well, turns out LinqKit is going to be useful for my project in other areas. So thanks, and answer credit to you! :-)Dislike
S
0

Are you sure you need to use an Expression? If you don't need different Linq providers to convert code trees into queries, then consider using just Func, instead. If you just use Func so that the method signatures are:

public static Func<Customer, CustomerContact> GetCustomerContact();

and

public static Func<Customer, CustomerContact> GetCustomerContact();

Then your syntax would be fine for constructing the second Func off of the first one. Of course, this will only work for in-memory objects (with Linq-to-objects).

The problem is that in order to build an Expression, you have to explicitely build the evaluation tree, which can be quite hairy (using the various static methods on Expression). Because of this hairiness, there are several helper packages, including LINQKit.

Supercilious answered 2/6, 2013 at 9:27 Comment(2)
Yeah, I do need an Expression; I want the query to run SQL-side.Dislike
Then go with Ani's solution!Supercilious

© 2022 - 2024 — McMap. All rights reserved.