我已经使用基于lamdas之前,C#则表达式,但我没有经验手工将它们组成。给定一个Expression<Func<SomeType, bool>> originalPredicate,我想创建一个Expression<Func<OtherType, bool>> translatedPredicate

在这种情况下SOMETYPE和OTHERTYPE具有相同的字段,但(基于一个共同的接口上没有继承和不)它们是不相关的。

背景:我有一个基于LINQ to SQL的一个仓库实现。我投射的LINQ to SQL实体我的模型实体,以保持我的POCO模型。我想表达传递到存储库(作为规范的形式),但他们应基于模型的实体。但是,我无法通过这些表达式的数据上下文,因为它基于所述LINQ到SQL实体期望表达式。

有帮助吗?

解决方案

通过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到SQL确实

另一种选择是重建表达式树的完全下,使用反射来找到对应的成员。复杂得多。

其他提示

有一个其他的方式,我发现,还包括包装原来的委托。

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

有是做翻译没有含蓄的方式。你必须包装,从参数类型创建一个新的lambda内现有的委托:

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

其中OtherTypeFromSomeTypeOtherType参数创建SomeType实例。

我有同样的问题,因为你和我一起EF固定这样的:

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

实体框架知道如何构建正确的SQL命令。转换表达要复杂得多,因为它是建立为不可变的,并可能导致意外的运行时间的影响,如果你做错事,而且,在我的情况下,至少,它不需要。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top