在C# 4.0中的动态与真实代理技术中的方法缺失问题

13 浏览
0 Comments

在C# 4.0中的动态与真实代理技术中的方法缺失问题

有人知道如何使用RealProxy拦截动态方法调用(特别是那些将引发RuntimeBinderException异常的方法)吗?我希望捕获异常并在此基础上实现“方法丢失”,但似乎在拦截器生效之前会抛出异常。

我的测试代码看起来像这样:

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

其中DynamicObject上实际上没有实现“World”方法。拦截器非常直接 - 我希望检查IMethodReturnMessage.Exception中是否有RuntimeBinderException,并将其转发至类似以下内容的内容:

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

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

如果那样行不通 - 有人知道是否有.NET 4.0上已经运行良好并处理了这个问题的DynamicProxy版本吗?

admin 更改状态以发布 2023年5月24日
0
0 Comments

我会先讲一个详细的答案。在C#中,每个动态操作大致都会按以下顺序执行这三个步骤:

  1. 如果对象实现了IDynamicMetaObjectProvider接口或是COM对象,则请求对象自行绑定,如果失败,则...
  2. 使用反射将操作绑定到一个普通的CLR对象上,如果失败,则...
  3. 返回一个表示完全无法绑定的DynamicMetaObject对象。

你会看到GetType调用,因为在第2步中,C#运行时绑定程序正在反射您以尝试确定是否有适合调用的"World"方法,这是因为如果hello的IDynamicMetaObjectProvider实现没有提供任何特殊操作,则会发生此情况。

很不幸,抛出RuntimeBinderException异常的时候,我们已经无法进行绑定了。这个异常是在动态操作的执行阶段中,响应于由第3步返回的元对象时引发的。你唯一能够捕获它的机会就是在实际的调用点。

所以,如果你想在C#中实现method_missing,那么这种策略对你来说行不通。不过你还是有一些选择的。

一个简单的选择是在你的MethodMissingInterceptor中实现IDynamicMetaObjectProvider,并委托给被包装对象的IDMOP实现。如果内部IDMOP失败,那么你就可以绑定到任何你想要的东西(也许是调用拦截器中存储的method_missing委托)。这里的缺点是,这仅适用于已知是动态对象的对象,例如那些一开始就实现了IDMOP的对象。这是因为你实际上是将自己插入步骤1和2之间。

另一个我想到的替代方案是实现IDynamicMetaObjectProvider,并在其中积极响应每一个绑定,返回调用一种方法的调用方式,该方法(a)产生与C#编译器在第一次绑定时产生的相同代码,(b)捕获RuntimeBinderException,以调用method_missing方法。这里的缺点是它会非常复杂--你需要根据C#运行时绑定程序程序集中的公共类型生成任意委托类型和使用它们的IL,这些类型实际上并不适用于公众消费。但至少你将获得所有操作的method_missing。

我确定还有其他我没有想到的策略,就像你似乎暗示要使用远程代理一样。但我无法想象它们是什么样子的,也无法确定它们是否成功。

问题的关键在于,C# 4.0没有设计来预见你的这种需求。特别是你不能很容易地在步骤2和3之间插入自己。这就带我到短答案,很抱歉,C# 4.0没有method_missing。

0