【问题标题】:Expression Trees with dynamic parameter具有动态参数的表达式树
【发布时间】:2015-04-29 12:44:42
【问题描述】:

我想转换这个:

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");

代码现在可以编译,但运行时出现问题。

我正在尝试获取target 的属性Name 的值,如果对象是dynamic,这可能有意义。

但由于target 被认为是object 类型,因此表达式会抛出一个错误,告诉我Name 不作为属性存在。

是否有用于获取动态属性的表达式?

【问题讨论】:

标签: c# .net c#-4.0 dynamic expression-trees


【解决方案1】:

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

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 的调用,不是吗?为什么是表达式树,如果你在最后编译它???
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-14
  • 2018-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多