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

c# expression-trees lambda linq-to-sql repository-pattern

Question

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.

Accepted Answer

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.


Popular Answer

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



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why