Pergunta

Ao inspecionar os delegados em C# e .NET em geral, notei alguns fatos interessantes:

Criar um delegado em C# cria uma classe derivada de MulticastDelegate com um construtor:

.method public hidebysig specialname rtspecialname instance 
   void .ctor(object 'object', native int 'method') runtime managed { }

O que significa que espera a instância e um ponteiro para o método. No entanto, a sintaxe da construção de um delegado em C# sugere que ele tem um construtor

new MyDelegate(int () target)

onde posso reconhecer int () Como uma instância de função (int *target() seria um ponteiro de função em C ++). Então, obviamente, o compilador C# escolhe o método correto do grupo de métodos definido pelo nome da função e constrói o delegado. Portanto, a primeira pergunta seria: de onde o compilador C# (ou o Visual Studio, para ser preciso) escolhe essa assinatura do construtor? Não notei nenhum atributo especial ou algo que faria uma distinção. Isso é algum tipo de compilador/visualstudio Magic? Se não, é o T (args) target Construção válida em C#? Não consegui conseguir nada para compilar, por exemplo:

int () alvo = myMethod;

é inválido, assim está fazendo qualquer coisa com MyMetod, por exemplo, chamando .ToString() nele (bem, isso faz algum sentido, pois esse é tecnicamente um método grupo, mas imagino que deveria ser possível escolher explicitamente um método lançando, por exemplo (int())MyFunction. Então, tudo isso é mágica puramente compiladora? Olhar para a construção através do refletor revela mais uma sintaxe:

Func cs $ 1 $ 0000 = novo func (null, (intptr) foo);

Isso é consistente com a assinatura do construtor desmontado, mas isso não compila!

Uma nota interessante final é que as aulas Delegate e MulticastDelegate tem mais alguns conjuntos de construtores:

.Method Family hideBysig SpecialName RTSpecialName Instância void .Ctor (classe System.Type Target, String 'Method') CIL gerenciado

Onde ocorre a transição de um ponteiro de instância e método para um tipo e um nome de método de string? Isso pode ser explicado pelo runtime managed Palavras -chave na assinatura do construtor de delegados personalizados, ou seja, o tempo de execução faz o trabalho aqui?

EDITAR: OK, então acho que devo reformular o que queria dizer com esta pergunta. Basicamente, estou sugerindo que não há apenas C# Compiler / CLR Magic envolvido na construção de delegados, mas também alguns Estúdio visual A magia, uma vez que o Intellisense vira uma nova sintaxe ao sugerir os argumentos do construtor e até esconde um deles (por exemplo, o refletor não usa essa sintaxe e construtor, nesse caso).

Eu queria saber se essa afirmação é verdadeira e se a sintaxe da instância da função tem algum significado mais profundo em C# ou é apenas algum formato constante implementado pela parte Magic Visual Studio para clareza (o que faz sentido, pois parece inválido C#)? Em suma, se eu estivesse implementando o Intellisense, devo fazer alguma mágica para delegados ou poderia construir a sugestão por algum mecanismo inteligente?

Edição final: Então, o consenso popular é que isso é realmente vs magia. Ver outros exemplos (veja o comentário de Marc Granell) de tais vs Comportamento me convence de que esse é o caso.

Foi útil?

Solução

O primeiro argumento é resolvido a partir da referência do objeto (ou null para métodos estáticos); Sem mágica lá.

Re the segundo argumento, no entanto - é um ponteiro não gerenciado (nativo int); em suma, não há alternativa direto C# sintaxe que pode usar este construtor - ele usa uma instrução IL específica (ldftn) para resolver a função dos metadados. No entanto, você pode usar Delegate.CreateDelegate para criar delegados via reflexão. Você também pode usar o IL emit (DynamicMethod etc), mas não é divertido.

Outras dicas

Você primeiro define o delegado (é assim que o Visual Studio conhece a assinatura do método de destino):

delegate void MyDelegate();

Então você constrói instâncias delegadas como esta:

MyDelegate method = new MyDelegate({method name});

// If this was the method you wanted to invoke:
void MethodToInvoke()
{
    // do something
}

MyDelegate method = new MyDelegate(MethodToInvoke);

C# escolhe automaticamente o método que corresponde à assinatura do delegado.

Editar: Quando o Intellisense do Visual Studio mostra o int () target Sugestão, está mostrando a assinatura dos métodos C# que você pode usar. O compilador C# traduz a representação C# para IL. A implementação da IL parecerá diferente, porque o IL não é uma linguagem de estilo C e o compilador C# fornece açúcar sintático para abstrair os detalhes da implementação.

Isso é apenas um palpite, então não me atire se eu estiver errado, mas acho que o Intellisense está recebendo a assinatura do método de destino do Invoke Método definido no delegado. Refletor mostra claramente que o Invoke método em System.Action<T> é:

[MethodImpl(0, MethodCodeType=MethodCodeType.Runtime)]
public virtual void Invoke(T obj);

Que é o mesmo que a sugestão de assinatura oferecida pelo IntelliSense. A mágica é Intellisense, ao ver um tipo de delegado, olha para o Invoke Método e sugere um construtor que leva um alvo que o corresponde.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top