Shaul Behr
Shaul Behr

Reputation: 38101

Syntax to refer a method returning an Expression to another method?

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?

Upvotes: 6

Views: 242

Answers (2)

Ben Reich
Ben Reich

Reputation: 16324

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.

Upvotes: 0

Ani
Ani

Reputation: 113472

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

Upvotes: 3

Related Questions