Para o estático, DispatchProxy.Create<T,TProxy>()
a documentação nos diz que:
Cria uma instância de objeto que deriva da classe
TProxy
e implementa a interfaceT
.
Ter o seguinte código de teste confirma que:
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
Então a parte interessante sobre o Invoke
método de acordo com os documentos :
Sempre que qualquer método no tipo de proxy gerado é chamado, esse método é invocado para despachar o controle.
Isso pode significar
proxy
.GetType()
.GetMethods(BindingFlags.NonPublic|BindingFlags.Public|BindingFlags.Instance|BindingFlags.Static)
.Select(x => x.Name)
o que nos dá
Foo Invoke DMethod GetType MemberwiseClone Finalize ToString É igual a GetHashCode
mas se testarmos se chamamos Invoke
tanto o método de interface quanto o método de classe de despacho:
proxy.Foo(); // In Invoke
((D)proxy).DMethod(); // nothing
Observando como DispatchProxy
o tipo de proxy gerado é implementado com um campo privado com uma matriz de MethodInfos que são usados nos métodos stub com chamadas para Invoke
ele, fará sentido que só possamos ter esse comportamento com métodos que podemos substituir.
É por isso que defini o DMethod como virtual
, mas aparentemente nenhum stub foi criado.
Isso significa que os documentos devem declarar:
Sempre que qualquer método de interface >>> no tipo de proxy gerado é chamado, este método é invocado para despachar o controle.
Alterar "qualquer método" para "qualquer método de interface" ainda seria impreciso.
Suponha que haja uma segunda interface
I2
eD
a implemente.A chamada para
Bar
(claramente um "método de interface")Invoke
também não faz com que seja chamado.Eu interpretaria "o tipo de proxy gerado" como
typeof(I)
, em vez deproxy.GetType()
, já que esse é o tipo de retorno deCreate
.Isso corresponde à implementação de
Create
, onde apenas os métodos deT
(o primeiro parâmetro de tipo deCreate
) e suas superinterfaces são levados em consideração. ( fonte )Claro, concordo que a documentação poderia ser redigida melhor. Uma redação mais precisa (mas IMO mais complicada) seria:
Nota lateral: obter/definir propriedades/indexadores da interface e adicionar/remover manipuladores de eventos de eventos da interface também causaria
Invoke
a chamada. Mas essas operações tecnicamente ainda estão chamando algum tipo de método "por baixo dos panos" no nível de IL. Então, do ponto de vista da linguagem C#, não é apenas "qualquer método ". Dito isso, se a documentação mencionasse todas essas possibilidades, ficaria ainda mais complicado.