【问题标题】:Method-missing difficulties in C# 4.0: dynamic vs RealProxyC# 4.0 中缺少方法的困难:动态与 RealProxy
【发布时间】:2009-06-07 10:38:40
【问题描述】:

有人知道用RealProxy 拦截dynamic 方法调用(尤其是那些将引发RuntimeBinderExceptions 的方法调用)的方法吗?我希望捕获异常并在此基础上实现“缺少方法”,但它似乎在拦截器查看之前被抛出。

我的测试看起来像:

dynamic hello = MethodMissingInterceptor<DynamicObject>.Create();
Assert.AreEqual("World", hello.World());

World 实际上并未在 DynamicObject 上实现。拦截器非常简单 - 我希望检查 IMethodReturnMessage.Exception 中的 RuntimeBinderException 并转发到类似的内容:

public IMessage MethodMissing(IMethodCallMessage call)
{
    return new ReturnMessage(call.MethodBase.Name, new object[0], 0, call.LogicalCallContext, call);
}

不幸的是,我在拦截器中看到的只是对GetType 的一些调用,而不是不存在的World 方法。

如果失败了 - 有没有人知道是否有一个 DynamicProxy 版本在 .NET 4.0 上运行良好但可能已经解决了这个问题?

【问题讨论】:

    标签: c# dynamic proxy c#-4.0 method-missing


    【解决方案1】:

    我将从长答案开始。 C# 中动态操作的每个绑定都按以下顺序大致执行以下三件事:

    1. 如果对象实现了 IDynamicMetaObjectProvider 或者是 COM 对象,则要求对象绑定自身,如果失败,则...
    2. 使用反射将操作绑定到对普通旧 clr 对象的操作,如果失败,则...
    3. 返回一个表示绑定完全失败的 DynamicMetaObject。

    您会看到 GetType 调用,因为在第 2 步中,C# 运行时绑定器正在反映您是否有适合调用的“World”方法,这是因为 IDynamicMetaObjectProvider 实现你好,如果有的话,想不出有什么特别的事情要做。

    不幸的是,在抛出 RuntimeBinderException 时,我们不再绑定。异常来自动态操作的执行阶段,以响应由于步骤 3 返回的元对象。您捕获它的唯一机会是在实际调用站点。

    因此,如果您想在 C# 中实现 method_missing,那么该策略对您来说是行不通的。不过,您确实有一些选择。

    一个简单的选择是在您的 MethodMissingInterceptor 中实现 IDynamicMetaObjectProvider,并遵循包装对象的 IDMOP 实现。如果内部 IDMOP 发生故障,您可以绑定到您想要的任何内容(可能是对存储在拦截器中的 method_missing 委托的调用)。这里的缺点是这只适用于已知为动态对象的对象,例如那些开始实施 IDMOP 的人。这是因为您基本上是在第 1 步和第 2 步之间插入自己。

    我能想到的另一种选择是实现 IDynamicMetaObjectProvider,并在其中积极响应每个绑定,返回对(a)生成与 C# 编译器首先绑定的相同代码的方法的调用,并且 (b) 捕获 RuntimeBinderException 以调用 method_missing 方法。这里的缺点是它会非常复杂——您需要针对 C# 运行时绑定程序集中的公共类型生成任意委托类型和使用它们的 IL,坦率地说,这些类型不适合公共使用。但至少你会在所有操作中丢失方法。

    我确信还有其他我没有想到的策略,例如您似乎暗示要使用远程代理。我无法想象它们长什么样,也不能说它们是否会成功。

    这里问题的症结在于,C# 4.0 的设计没有预料到您希望这样做。具体来说,您不能轻易地将自己插入到第 2 步和第 3 步之间。这让我得到了简短的回答,很抱歉,C# 4.0 没有 method_missing。

    【讨论】:

    • 感谢克里斯的出色解释 - 我刚刚开始浏览您博客上的一系列 C#“动态”帖子。 :) 就我的目的而言,您的第一个解决方案听起来应该可行。我真的只想对构建器样式的对象进行这些调用,并且为了在测试 API 时更加流畅,我不需要在任意对象上捕获它们。
    • 有没有办法只查询动态对象是否存在成员而不实际调用它?
    • @Chris - 还要注意上面的“以防万一”的问题;实际上,我很想知道;-p
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 2019-02-21
    • 1970-01-01
    • 2010-10-29
    相关资源
    最近更新 更多