C# 4.0 中方法缺失的困难:动态与 RealProxy
有谁知道如何使用 RealProxy 拦截动态方法调用(特别是那些将引发 RuntimeBinderException 的调用)? 我希望捕获异常并在此基础上实现“方法丢失”,但它似乎在拦截器查看之前被抛出。
我的测试看起来像:
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);
}
不幸的是,我在拦截器中看到的只是对 IMethodReturnMessage.Exception 的一些调用code>GetType
,而不是不存在的 World
方法。
如果失败了 - 有谁知道是否有一个在 .NET 4.0 上运行良好的 DynamicProxy
版本可能已经解决了这个问题?
Does anyone know of a way to intercept dynamic
method calls (particularly those that are going to raise RuntimeBinderException
s) with a RealProxy
? I was hoping to catch the exception and implement 'method missing' on top of that, but it appears to be thrown before the interceptor gets a look-in.
My test just looks like:
dynamic hello = MethodMissingInterceptor<DynamicObject>.Create();
Assert.AreEqual("World", hello.World());
Where World
isn't actually implemented on DynamicObject
. The interceptor is pretty straightforward - I was hoping to check IMethodReturnMessage.Exception
for RuntimeBinderException
and forward on to something like:
public IMessage MethodMissing(IMethodCallMessage call)
{
return new ReturnMessage(call.MethodBase.Name, new object[0], 0, call.LogicalCallContext, call);
}
Unfortunately, all I see in my interceptor are some calls to GetType
, and not the non-existant World
method.
Failing that - does anyone know if there's a DynamicProxy
version running happily on .NET 4.0 yet that might have tackled the problem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我将从长答案开始。 C# 中动态操作的每次绑定大约按以下顺序执行以下三件事:
您看到 GetType 调用是因为在步骤 2 中,C# 运行时绑定器正在向您反映,试图确定是否有适合调用的“World”方法,而发生这种情况是因为 IDynamicMetaObjectProvider 实现了 hello,如果有的话,也想不出什么特别的事情可做。
不幸的是,当抛出 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。
I'll start with the long answer. Every bind of a dynamic operation in C# does approximately these three things in this order:
You're seeing the GetType calls because in step 2, the C# runtime binder is reflecting over you to try to figure out if you have a "World" method that is appropriate to call, and this is happening because the IDynamicMetaObjectProvider implementation of hello, if there is one, couldn't come up with anything special to do.
Unfortunately for you, by the time the RuntimeBinderException is thrown, we are no longer binding. The exception comes out of the execution phase of the dynamic operation, in response to the meta object returned due to step 3. The only opportunity for you to catch it is at the actual call site.
So that strategy isn't going to work out for you if you want to implement method_missing in C#. You do have some options though.
One easy option is to implement IDynamicMetaObjectProvider in your MethodMissingInterceptor, and defer to the IDMOP implementation of the wrapped object. In case of failure on the part of the inner IDMOP, you can bind to whatever you want (perhaps a call to a method_missing delegate stored in the interceptor). The downside here is that this only works for objects that are known to be dynamic objects, e.g. those that implement IDMOP to begin with. This is because you are basically inserting yourself between steps 1 and 2.
Another alternative I can think of is to implement IDynamicMetaObjectProvider, and in it, respond positively to every bind, returning a call to a method that (a) produces the same code the C# compiler would have produced to bind in the first place, and (b) catches RuntimeBinderException to call a method_missing method. The downside here is that it would be quite complicated--you'd need to generate arbitrary delegate types and the IL that uses them, against the public types in the C# runtime binder assembly which, frankly, are not meant for public consumption. But at least you'd get method missing against all operations.
I am sure there are other strategies I have not thought of, such as you seem to be hinting at about using remoting proxies. I can't imagine what they look like though and I can't say if they'd be successful.
The crux of the problem here is that C# 4.0 does not have a design that anticipates your desire to do this. Specifically, you cannot easily insert yourself between steps 2 and 3. That brings me to the short answer, which is sorry, C# 4.0 does not have method_missing.