'C# How to convert an Expression<Func<SomeType>> to an Expression<Func<OtherType>>

I have used C# expressions before based on lamdas, but I have no experience composing them by hand. Given an Expression<Func<SomeType, bool>> originalPredicate, I want to create an Expression<Func<OtherType, bool>> translatedPredicate.

In this case SomeType and OtherType have the same fields, but they are not related (no inheritance and not based on a common interface).

Background: I have a repository implementation based on LINQ to SQL. I project the LINQ to SQL entities to my Model entities, to keep my model in POCO. I want to pass expressions to the repository (as a form of specifications) but they should be based on the model entities. But I can't pass those expressions to the data context, since it expects expressions based on the LINQ to SQL entities.



Solution 1:[1]

With Expression, the simplest way is with a conversion expression:

class Foo {
    public int Value { get; set; }
}
class Bar {
    public int Value { get; set; }
}
static class Program {
    static void Main() {
        Expression<Func<Foo, bool>> predicate =
            x => x.Value % 2 == 0;
        Expression<Func<Bar, Foo>> convert =
            bar => new Foo { Value = bar.Value };

        var param = Expression.Parameter(typeof(Bar), "bar");
        var body = Expression.Invoke(predicate,
              Expression.Invoke(convert, param));
        var lambda = Expression.Lambda<Func<Bar, bool>>(body, param);

        // test with LINQ-to-Objects for simplicity
        var func = lambda.Compile();
        bool withOdd = func(new Bar { Value = 7 }),
             withEven = func(new Bar { Value = 12 });
    }
}

Note however that this will be supported differently by different providers. EF might not like it, for example, even if LINQ-to-SQL does.

The other option is to rebuild the expression tree completely, using reflection to find the corresponding members. Much more complex.

Solution 2:[2]

There is one other way I have found, that also includes wrapping your original delegate.

Func<T, object> ExpressionConversion<U>(Expression<Func<T, U>> expression)
{
    Expression<Func<T, object>> g = obj => expression.Compile().Invoke(obj);
    return g.Compile();
}

Solution 3:[3]

There is no implicit way to do the translation. You have to wrap your existing delegate inside a lambda that creates a new type from the argument type:

var translatedPredicate = x => originalPredicate(OtherTypeFromSomeType(x))

Where OtherTypeFromSomeType creates the OtherType instance from the SomeType argument.

Solution 4:[4]

In my case, I had the same inconvenience, the problem was that I was using AutoMapper to pass information from one class to another and in this case @Marc-Gravell's solution did not work for me with AutoMapper, but doing some research I found that AutoMapper can convert Expression<Func<OrderLineDTO, bool>> to Expression<Func<OrderLine, bool>>

public class OrderLine
{
  public int Id { get; set; }
  public int OrderId { get; set; }
  public decimal Quantity { get; set; }
}

public class OrderLineDTO
{
  public int Id { get; set; }
  public int OrderId { get; set; }
  public decimal Quantity { get; set; }
}

The AutoMapper configuration would be the following

var config = new MapperConfiguration(cfg =>
{
    cfg.AddExpressionMapping();

    cfg.CreateMap<OrderLine, OrderLineDTO>();
    cfg.CreateMap<OrderLineDTO, OrderLine>();
});

var mapper = config.CreateMapper();

And finally, perform the conversion


Expression<Func<OrderLineDTO, bool>> expression = e => e.OrderId == 102;

Expression<Func<OrderLine, bool>> convertedExpression = mapper.Map<Expression<Func<OrderLine, bool>>>(expression);

This code depends on AutoMapper and AutoMapper.Extensions.ExpressionMapping

For more information, you can see the documentation of AutoMapper and to perform the expressions

Solution 5:[5]

I had the same issue as you and i fixed it like this with EF:

var viewModeValue = dbContext.Model.Select(m => new ViewModel{Field = m.Field}).Where(predicate) //predicate is an Expression<Func<ViewModel, bool>>

Entity Framework knows how to build the correct sql command. Converting the expression is much more complicated, because it is built to be immutable and could cause undesired run time effects if you do something wrong, and, in my case at least, it is not needed.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Marc Gravell
Solution 2 Aaroninus
Solution 3 Konrad Rudolph
Solution 4 kuudev
Solution 5 Eremencu Adrian