【问题标题】:Correct way to construct .NET Expression to invoke dynamic objects构造 .NET 表达式以调用动态对象的正确方法
【发布时间】:2014-04-19 20:35:52
【问题描述】:

我需要创建一个调用动态对象的System.Linq.Expressions.Expression。动态对象可以是ExpandoObject 或任何其他IDynamicMetaObjectProvider

考虑以下测试:

var myInstance = DateTime.Now;

var methodInfo = myInstance.GetType().GetMethod("ToUniversalTime");

var methodCallExpression = Expression.Call(Expression.Constant(myInstance), methodInfo);
var expression = Expression.Lambda(methodCallExpression);

Assert.AreEqual(myInstance.ToUniversalTime(), expression.Compile().DynamicInvoke());

当 myInstance 被声明为类似(仅作为示例)时,我需要创建一个等效表达式:

dynamic myInstance = new ExpandoObject();
myInstance.MyMethod = new Func<string>(() => "hello world");

我想我需要使用Expression.Dynamic 方法(参见MSDN)。但我不知道如何使用它。我曾尝试在 google 上搜索,但我发现的唯一示例使用无法正式使用的 Microsoft.CSharp.RuntimeBinder.Binder 类(请参阅 MSDN):

此 API 支持 .NET Framework 基础结构,不能直接从您的代码中使用。

使用Microsoft.CSharp.RuntimeBinder.Binder我可以编写如下代码:

dynamic myInstance = new ExpandoObject();
myInstance.MyMethod = new Func<string>(() => "hello world");

var binder = Binder.InvokeMember(
    CSharpBinderFlags.None,
    "MyMethod",
    null,
    this.GetType(),
    new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant, null) });

var methodCallExpression = Expression.Dynamic(binder, typeof(object), Expression.Constant(myInstance));
var expression = Expression.Lambda(methodCallExpression);

Assert.AreEqual(myInstance.MyMethod(), expression.Compile().DynamicInvoke());

这个解决方案正确吗?

【问题讨论】:

  • 是的,这就是我在 CSharpEval 中实现它的方式

标签: c# .net dynamic lambda


【解决方案1】:

这里有一个问题:据我了解,没有某种Binder 对象进行动态调用是没有意义的。

binder 对象表示动态名称解析遵循的规则:

  • 匹配是否应该区分大小写?
  • 应如何解决方法重载?
  • 如果对象是非动态对象怎么办?
  • 您使用哪些后备方案?

也就是说,Binder 对象表示调用“语言”的语义,而IDynamicMetaObjectProvider 表示被调用对象的语义。

所以,是的,我们不应该使用 CSharp Binder 对象。尤其是当一些问题发生时,只能通过使用对象的内部来解决。但是,另一种方法是简单地使用另一个非框架提供的Binder 实现。

【讨论】:

    【解决方案2】:
      dynamic x = typeof("<<MethodName>>")
                .GetMethod("ToUniversalTime")
                .Invoke(<<Type Of Object>>, new object[] { [Parameter1,]                    
                [Parameter2,....] }); 
    

    在此代码中“类型”,而不是您必须从哪种类型的对象调用方法...

    指定您的方法名称而不是“MethodName”

    最后是你的对象而不是“对象类型”

    如果没有参数,则传递空数组...否则传递而不是“参数1,2,依此类推。

    【讨论】:

    • 我正在寻找一种构建表达式树的方法,请参阅表达式类。您的代码只需通过反射调用方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多