6

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

我的测试看起来像:

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

WhereWorld实际上没有在DynamicObject. 拦截器非常简单 - 我希望检查IMethodReturnMessage.ExceptionRuntimeBinderException转发到类似的内容:

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

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

如果做不到这一点 - 有谁知道是否有一个DynamicProxy版本可以在 .NET 4.0 上愉快地运行,但可能已经解决了这个问题?

4

1 回答 1

17

我将从长答案开始。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。

于 2009-06-10T00:32:49.400 回答