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

Michiel van Oosterhout picture Michiel van Oosterhout · Mar 17, 2009 · Viewed 13.3k times · Source

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.

Answer

Marc Gravell picture Marc Gravell · Mar 17, 2009

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.