C#如何转换表达式<func <sometype>&gt;到表达式<func <othertype>&gt; </func <othertype> </func <sometype>

时间:2009-03-17 13:06:05

标签: c# linq-to-sql lambda repository-pattern expression-trees

我之前使用过基于lamdas的C#表达式,但我没有手工编写它们的经验。鉴于Expression<Func<SomeType, bool>> originalPredicate,我想创建一个Expression<Func<OtherType, bool>> translatedPredicate

在这种情况下,SomeType和OtherType具有相同的字段,但它们不相关(没有继承而不是基于公共接口)。

背景:我有一个基于LINQ to SQL的存储库实现。我将LINQ to SQL实体投影到我的Model实体,以便将我的模型保存在POCO中。我想将表达式传递给存储库(作为规范的一种形式),但它们应该基于模型实体。但我无法将这些表达式传递给数据上下文,因为它需要基于LINQ to SQL实体的表达式。

4 个答案:

答案 0 :(得分:21)

使用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 });
    }
}

但请注意,不同提供商将以不同方式支持此功能。例如,EF可能不喜欢它,即使LINQ-to-SQL也是如此。

另一个选项是重建表达式树完全,使用反射来查找相应的成员。更加复杂。

答案 1 :(得分:3)

我找到了另外一种方法,其中还包括包装原始代表。

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

答案 2 :(得分:2)

没有隐含的方法来进行翻译。您必须将现有委托包装在lambda中,该lambda从参数类型创建一个新类型:

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

OtherTypeFromSomeTypeOtherType参数创建SomeType实例的位置。

答案 3 :(得分:0)

我和你有同样的问题,我用EF解决了这个问题:

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

实体框架知道如何构建正确的sql命令。转换表达式要复杂得多,因为它构建为不可变的,并且如果你做错了会导致不希望的运行时效果,至少在我的情况下,它是不需要的。