C#如何将Expression <Func >转换为Expression <Func >

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

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

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

使用Expression ,最简单的方法是使用转换表达式

 class Foo { public int Value { get; set; } } class Bar { public int Value { get; set; } } static class Program { static void Main() { Expression> predicate = x => x.Value % 2 == 0; Expression> 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>(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 }); } } 

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

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

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

 Func ExpressionConversion(Expression> expression) { Expression> g = obj => expression.Compile().Invoke(obj); return g.Compile(); } 

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

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

OtherTypeFromSomeTypeSomeType参数创建OtherType实例。

我遇到了和你一样的问题,我用EF解决了这个问题:

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

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