如何组合动态类型的表达式

How to Combine Expressions of dynamic Types

提问人:BeanFlicker 提问时间:9/25/2023 最后编辑:Ken WhiteBeanFlicker 更新时间:9/27/2023 访问量:42

问:

我想看看我是否可以 AndAlso 两个类型的 dynamic 表达式。与我实际正在做的事情相比,这个示例非常简单,但它传达了这一点。我见过的所有使用 PedicateBuilder 或 ExpressionBuilder 的示例都要求表达式为 bool 类型,并且通常用作“Where”子句。这个对象正在返回一个新的动态对象。

public class MyObject
{
    public string Name { get; set; }
    public string Value { get; set; }   
    public string Comment { get; set; } 
}

Expression<Func<MyObject, dynamic>> e1 = i => new { MyName = i.Name };
Expression<Func<MyObject, dynamic>> e2 = i => new { MyValue = i.Value };

我希望得到 e1 和 & e2 的组合表达式。我这样做的方式正确吗?

更新1:我已经尝试了这个答案,但它需要输入为 MemberInitExpression,并且我有 NewExpression,它不包含所需的绑定

C# LINQ 表达式 C#-10.0

评论

0赞 NetMage 9/26/2023
静态类型是 (即 ),但运行时类型将是编译器使用单个属性创建的匿名类。同样。这些不能与那只是一个运行时错误。(静态尝试所需的内容,并在运行时看到错误。你想完成什么?e1dynamicobjecte2AndAlso
0赞 BeanFlicker 9/26/2023
我正在尝试将 e1 和 e2 组合成包含 MyName 和 MyValue 属性的 e3
0赞 NetMage 9/26/2023
C# 是一种类型语言,与 和 有类型无关。为什么你认为布尔运算符在这里是相关的?(尝试的结果是什么:?dynamice1e2&&(new { MyName = "a" }) && (new { MyValue = "b" })
0赞 NetMage 9/26/2023
如果你可以做你想做的事,你希望结果是什么(运行时)类型?您没有具有这两个属性的现有匿名类型,您是否希望在运行时创建一个新类型(可能,但需要做很多工作,而且很少值得 - 事实上,使用很少值得。dynamic
0赞 BeanFlicker 9/27/2023
@NetMage - 我明白你为什么一直问我为什么要这样做。这是无关紧要的。我想知道我是否可以做到这一点。我知道 AndAlso 适用于布尔类型,但事实并非如此。我也明白动态本身就是一种类型。我很好奇我是否可以将这两个表达式合并在一起,并从中得到一个组合表达式

答:

-1赞 NetMage 9/27/2023 #1

鉴于

Expression<Func<MyObject, dynamic>> e1 = i1 => new { MyName = i1.Name };
Expression<Func<MyObject, dynamic>> e2 = i2 => new { MyValue = i2.Value };

您可以创建一个新的匿名类型,该类型将同时具有这两个属性。我将手动创建它:

var mo = new MyObject();
mo.Name = "a";
mo.Value = "1";
var make_e1_2 = new { MyName = mo.Name, MyValue = mo.Value };

然后,您可以从 和 中提取参数和正文,并使用它们来调用新的类型构造函数:e1e2

// (MyObject i1)
var e1_2Parm = e1.Parameters[0];

// new { MyName = i1.Name }
var e1Body = (NewExpression)e1.Body;
// new { MyValue = i1.Value }
var e2Body = (NewExpression)e2.Body.Replace(e2.Parameters[0], e1_2Parm);

// .ctor(string MyName, string MyValue)
var e1_2Constructor = make_e1_2.GetType().GetConstructors().First();

// new { MyName = i1.Name, MyValue = i1.Value }
var e1_2Body = Expression.New(e1_2Constructor, e1Body.Arguments[0], e2Body.Arguments[0]);

// (MyObject i1) => new { MyName = i1.Name, MyValue = i1.Value }
var e1_2 = Expression.Lambda<Func<MyObject, dynamic>>(e1_2Body, e1_2Parm);

此代码假定存在一个标准扩展,该扩展将任何出现的扩展替换为另一个。 您可以轻松编写自己的课程,也可以使用EF Core课程来创建一个。ExpressionVisitorExpressionReplace()ReplacingExpressionVisitor