对于静态,文档DispatchProxy.Create<T,TProxy>()
告诉我们:
创建一个从类派生
TProxy
并实现接口的对象实例T
。
有以下测试代码可以确认:
interface I{
void Foo();
}
class D : DispatchProxy {
protected override object Invoke(MethodInfo targetMethod, object[] args) {
Console.WriteLine("In Invoke");
return null;
}
public virtual void DMethod(){
}
}
var proxy = DispatchProxy.Create<I,D>();
Console.WriteLine(proxy.GetType().BaseType); // typeof(D)
Console.WriteLine(proxy is I); // true
Invoke
然后根据文档,关于该方法的有趣部分是:
每当调用生成的代理类型上的任何方法时,都会调用此方法来调度控制。
这可能意味着
proxy
.GetType()
.GetMethods(BindingFlags.NonPublic|BindingFlags.Public|BindingFlags.Instance|BindingFlags.Static)
.Select(x => x.Name)
这给了我们
Foo 调用 DMethod GetType MemberwiseClone 完成 ToString 等于 GetHashCode
但是如果我们测试是否调用了Invoke
接口方法和调度类方法:
proxy.Foo(); // In Invoke
((D)proxy).DMethod(); // nothing
查看DispatchProxy
生成的代理类型是如何使用私有字段来实现的,该私有字段包含一个 MethodInfos 数组,这些数组在调用它的存根方法中使用,Invoke
这将使我们只能使用可以覆盖的方法来实现这种行为。
这就是为什么我将 DMethod 定义为virtual
,但显然没有创建存根。
这是否意味着文档应该说明:
每当调用生成的代理类型上的任何 >>>接口方法时,都会调用此方法来调度控制。
将“任何方法”更改为“任何接口方法”仍然是不准确的。
假设有第二个接口
I2
,并D
实现该接口。Bar
对(显然是“接口方法”)的调用Invoke
也不会导致被调用。我会将“生成的代理类型”解释为
typeof(I)
,而不是proxy.GetType()
,因为这是的返回类型Create
。这与的实现相匹配,其中只考虑了(的第一个类型参数)
Create
的方法及其超接口。(来源)T
Create
当然,我同意文档的措辞可以更好。更准确(但在我看来更复杂)的措辞应该是:
附注:获取/设置接口的属性/索引器,以及添加/删除接口事件的事件处理程序也会导致
Invoke
调用。但这些操作在技术上仍然是在 IL 级别“幕后”调用某种方法。因此从 C# 语言的角度来看,它不仅仅是“任何方法”。也就是说,如果文档提到了所有这些可能性,它会变得更加复杂。