动态参数的表达式树

9

我希望你能够将这个转换:

Func<dynamic, object> myFunc = t => return t.Name + " " + t.Surname;

转换为表达式树。

我想到的是这样:

ParameterExpression target = ExpressionParameter(typeof(dynamic), "target");
ParameterExpression result = ExpressionParameter(typeof(object), "result");
BlockExpression block = Expression.Block(
     new [] { result },
     Expression.Assign(
           result,
           Expression.Add(
                 Expression.Add(
                      Expression.Property(target, "Name"),
                      Expression.Constant(" ", typeof(string))
                 ),
                 Expression.Property(target, "Surname")
           )
     )
);
Func<dynamic, object> myFunc = Expression.Lambda<dynamic, object>>(block, target).Compile();

然而,编译器不喜欢typeof(dynamic),我有点理解。 dynamic不是一种类型,本质上是一个object
因此,我继续更改了ParameterExpression
ParameterExpression target = ExpressionParameter(typeof(object), "target");

代码现在可以编译,但在运行时存在一个问题。
我尝试获取目标对象的属性“Name”的值,如果对象是“dynamic”的话可能有意义。
但由于将“target”认为是“object”类型,表达式会抛出错误,告诉我“Name”不存在作为属性。
是否有一种表达式可以获取动态属性?

请看这个问题:https://dev59.com/1nA65IYBdhLWcg3w7DP8 它涉及动态和表达式树。 - Cyril Durand
1个回答

6

对于那些对解决方案感兴趣的人:

ParameterExpression target = Expression.Parameter(typeof(object), "target");
ParameterExpression result = Expression.Parameter(typeof(object), "result");

CallSiteBinder getName = Binder.GetMember(
   CSharpBinderFlags.None, "Name", typeof(Program),
   new CSharpArgumentInfo[] {
       CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
   }
);

CallSiteBinder getSurname= Binder.GetMember(
   CSharpBinderFlags.None, "Surname", typeof(Program),
   new CSharpArgumentInfo[] {
       CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
   }
);

BlockExpression block = Expression.Block(
    new[] { result },
    Expression.Assign(
        result,
        Expression.Call(typeof(string).GetMethod("Concat", new Type[] { typeof(object[]) }),
                        Expression.NewArrayInit(typeof(object),
                             Expression.Dynamic(getName, typeof(object), target),
                             Expression.Constant(" ", typeof(object)),
                             Expression.Dynamic(getSurname, typeof(object), target)
                        )
       )
    )
);

Func<dynamic, object> myFunc = Expression.Lambda<Func<dynamic, object>>(block, target).Compile();

以下是我的具体操作步骤:
  1. 创建了一个 CallSiteBinder,用于获取作为参数传递的动态对象的动态属性 Name 的值。
  2. 创建了一个 CallSiteBinder,用于获取作为参数传递的动态对象的动态属性 Surname 的值。
  3. 调用了方法 string.Concat(params object[] args)。为此,我需要将我的参数作为 object 数组发送。我正在使用 getName" "getSurname 的值创建数组。
我使用以下答案作为指南和参考:

C# 4 “dynamic” in expression trees

通过以上方法,可以做到像下面这样:
dynamic person = new ExpandoObject();
person.Name = "Matt";
person.Surname = "Smith";

object value = myFunc(person);
Console.WriteLine(value); //Will print out "Matt Smith"

//Internally it just calls:
//string.Concat(new object[] { person.Name, " ", person.Surname });

为什么要使用块表达式?你可以直接将lambda的主体作为调用concat的语句,不是吗? 为什么要使用表达式树,最终还是要编译它呢? - MBoros

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接