方法缺少C#4.0中的困难:动态与RealProxy

时间:2009-06-07 10:38:40

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

是否有人知道如何使用dynamic拦截RuntimeBinderException方法调用(特别是那些将会RealProxy提升的方法)?我希望捕获异常并在其上实现'方法缺失',但它似乎在拦截器获得查看之前被抛出。

我的测试看起来像:

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方法。

失败了 - 有没有人知道是否有一个{{1}}版本在.NET 4.0上运行得很快但可能解决了这个问题?

1 个答案:

答案 0 :(得分:17)

我将从冗长的答案开始。 C#中动态操作的每个绑定按以下顺序执行大约这三项操作:

  1. 如果对象实现了IDynamicMetaObjectProvider或者是一个COM对象,请让对象绑定自己,如果失败,那么......
  2. 使用反射将操作绑定到plain-old-clr-object上的操作,如果失败,则...
  3. 返回表示完全无法绑定的DynamicMetaObject。
  4. 您正在看到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方法。这里的缺点是它会非常复杂 - 你需要生成任意委托类型和使用它们的IL,而不是C#运行时绑定程序集中的公共类型,坦率地说,它不适合公共使用。但至少你会对所有操作都缺少方法。

    我确信还有其他一些我没有想过的策略,例如你似乎暗示使用远程代理。我无法想象它们看起来像什么,我不能说它们是否会成功。

    问题的关键在于C#4.0没有预期你想要这样做的设计。具体来说,你不能轻易地在第2步和第3步之间插入自己。这让我得到简短的回答,很抱歉,C#4.0没有method_missing。