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

Posted

技术标签:

【中文标题】C# 如何将 Expression<Func<SomeType>> 转换为 Expression<Func<OtherType>>【英文标题】:C# How to convert an Expression<Func<SomeType>> to an Expression<Func<OtherType>> 【发布时间】:2010-10-13 20:09:48 【问题描述】:

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

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

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

【问题讨论】:

回复在这个话题:***.com/questions/4601844/… 【参考方案1】:

使用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 喜欢。

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

【讨论】:

我希望 L2EF 喜欢这个,因为我将表达式从接口转换为具体类,并将结果作为 IQueryable 返回...你认为有办法吗减少开销? +1:这让我走上了我认为的正确道路。即便如此,我确实学到了一些新东西。我从 EF 那里得到了一个缺失的关系。在我提出一个新问题之前,我会做更多的工作。我想知道是否需要通过 EntityCollection 方法附加表格...【参考方案2】:

我发现了另一种方法,也包括包装您的原始委托。

Func<T, object> ExpressionConversion<U>(Expression<Func<T, U>> expression)

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

【讨论】:

【参考方案3】:

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

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

OtherTypeFromSomeTypeSomeType 参数创建OtherType 实例。

【讨论】:

问题是关于表达式,而不是代表。您不能使用这种方法来调用子表达式;它更复杂。 糟糕,没有仔细阅读。无论如何,技术基本相同,表达式只是需要更多的工作(即使从技术上讲,我的代码在第一次编译 originalPredicate 并使用 Expression&lt;…&gt; 而不是 var 后仍然可以工作;-))。【参考方案4】:

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

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

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

【讨论】:

以上是关于C# 如何将 Expression<Func<SomeType>> 转换为 Expression<Func<OtherType>>的主要内容,如果未能解决你的问题,请参考以下文章

了解C#的Expression

c# linq语句的Expression<Func<TEntity,bool>>怎么传进参数

从 c# 表达式中删除不需要的装箱转换

如何动态创建 Expression<Func<MyClass, bool>> 谓词?

如何从 Expression<Func<MyClass, string>> 动态创建 Expression<Func<MyClass, bool>> 谓

如何设置属性选择器的值 Expression<Func<T,TResult>>