C# 如何将 Expression<Func<SomeType>> 转换为 Expression<Func<OtherType>>
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/654153/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# How to convert an Expression<Func<SomeType>> to an Expression<Func<OtherType>>
提问by Michiel van Oosterhout
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
.
我之前使用过基于 lamdas 的 C# 表达式,但我没有手工编写它们的经验。给定一个Expression<Func<SomeType, bool>> originalPredicate
,我想创建一个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).
在这种情况下 SomeType 和 OtherType 具有相同的字段,但它们不相关(没有继承并且不基于公共接口)。
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.
背景:我有一个基于 LINQ to SQL 的存储库实现。我将 LINQ to SQL 实体投影到我的模型实体,以将我的模型保存在 POCO 中。我想将表达式传递给存储库(作为规范的一种形式),但它们应该基于模型实体。但我无法将这些表达式传递给数据上下文,因为它需要基于 LINQ to SQL 实体的表达式。
采纳答案by Marc Gravell
With Expression
, the simplest way is with a conversion expression:
使用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.
但是请注意,不同的提供商会对此提供不同的支持。例如,即使 LINQ-to-SQL 喜欢,EF 也可能不喜欢它。
The other option is to rebuild the expression tree completely, using reflection to find the corresponding members. Much more complex.
另一种选择是重建表达式树完全,使用反射来找到对应的成员。复杂得多。
回答by Konrad Rudolph
There is no implicit way to do the translation. You have to wrap your existing delegate inside a lambda that creates a new type from the argument type:
没有隐含的方法来进行翻译。您必须将现有委托包装在从参数类型创建新类型的 lambda 中:
var translatedPredicate = x => originalPredicate(OtherTypeFromSomeType(x))
Where OtherTypeFromSomeType
creates the OtherType
instance from the SomeType
argument.
从参数哪里OtherTypeFromSomeType
创建OtherType
实例SomeType
。
回答by sQuir3l
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();
}
回答by Eremencu Adrian
I had the same issue as you and i fixed it like this with EF:
我和你有同样的问题,我用 EF 解决了这个问题:
var viewModeValue = dbContext.Model.Select(m => new ViewModel{Field = m.Field}).Where(predicate) //predicate is an Expression<Func<ViewModel, bool>>
Entity Framework knows how to build the correct sql command. Converting the expression is much more complicated, because it is built to be immutable and could cause undesired run time effects if you do something wrong, and, in my case at least, it is not needed.
实体框架知道如何构建正确的 sql 命令。转换表达式要复杂得多,因为它被构建为不可变的,如果你做错了什么,可能会导致不希望的运行时影响,至少在我的情况下,它是不需要的。