Pregunta

Mientras inspeccionaba los delegados en C# y .NET en general, noté algunos hechos interesantes:

Crear un delegado en C# crea una clase derivada de MulticastDelegate con un constructor:

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

Lo que significa que espera la instancia y un puntero al método. Sin embargo, la sintaxis de construir un delegado en C# sugiere que tiene un constructor

new MyDelegate(int () target)

donde puedo reconocer int () como una función de función (int *target() sería un puntero de función en C ++). Entonces, obviamente, el compilador C# elige el método correcto del grupo de métodos definido por el nombre de la función y construye el delegado. Entonces, la primera pregunta sería, ¿de dónde elige el compilador C# (o Visual Studio, para ser precisos) de esta firma de constructor? No noté ningún atributo especial o algo que haría una distinción. ¿Es este algún tipo de compilador/VisualStudio Magic? Si no, es el T (args) target Construcción válida en C#? No logré conseguir nada para compilarlo, por ejemplo:

int () target = mymethod;

no es válido, por lo que está haciendo cualquier cosa con MyMetod, por ejemplo, llamadas .ToString() en él (bueno, esto tiene algún sentido, ya que ese es técnicamente un método grupo, pero me imagino que debería ser posible elegir explícitamente un método lanzando, por ejemplo, (int())MyFunction. Entonces, ¿es toda esta magia puramente compiladora? Mirar la construcción a través de reflector revela otra sintaxis:

Func cs $ 1 $ 0000 = nuevo func (nulo, (intptr) foo);

Esto es consistente con la firma del constructor desmontado, ¡pero esto no se compila!

Una última nota interesante es que las clases Delegate y MulticastDelegate tienen otro conjunto de constructores:

.Method Familia Hidebysig SpecialName rtSpecialName instancia void .ctor (class System.Type Target, String 'Method') CIL Managed

¿Dónde se produce la transición de un puntero de instancia y método a un tipo y un nombre de método de cadena? ¿Se puede explicar esto por el runtime managed Palabras clave en la firma de constructor de delegados personalizados, es decir, ¿el tiempo de ejecución hace su trabajo aquí?

EDITAR: OK, entonces supongo que debería reformular lo que quería decir con esta pregunta. Básicamente, estoy sugiriendo que no solo hay una magia de C# compilador / CLR involucrada en la construcción de delegados, sino también algunos Estudio visual Magia, ya que Intellisense voltea una nueva sintaxis al sugerir los argumentos del constructor e incluso oculta uno de ellos (por ejemplo, el reflector no usa esta sintaxis y construtor, para el caso).

Me preguntaba si esta afirmación es cierta, y si la sintaxis de la instancia de función tiene un significado más profundo en C# o es solo un formato constante implementado por Visual Studio Magic Part para claridad (lo que tiene sentido, ya que parece inválido C#)? En resumen, si estuviera implementando IntelliSense, ¿debería hacer algo de magia para los delegados o podría construir la sugerencia por algún mecanismo inteligente?

Edición final: Entonces, el consenso popular es que es de hecho frente a magia. Ver otros ejemplos (ver el comentario de Marc Gravell) de tal comportamiento vs me convence de que ese es el caso.

¿Fue útil?

Solución

El primer argumento se resuelve desde la referencia del objeto (o null para métodos estáticos); No hay magia allí.

Re the segundo argumento, sin embargo, es un puntero no administrado (intent int); En resumen, no hay alternativa directo C# sintaxis que puede usar este constructor: utiliza una instrucción IL específica (ldftn) para resolver la función de metadatos. Sin embargo, puedes usar Delegate.CreateDelegate Para crear delegados a través de la reflexión. También puedes usar IL EMIT (DynamicMethod etc), pero no es divertido.

Otros consejos

Primero define el delegado (así es como Visual Studio conoce la firma del método de destino):

delegate void MyDelegate();

Luego construyes instancias 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# elige automáticamente el método que coincide con la firma del delegado.

Editar: cuando el IntelliSense de Visual Studio te muestra el int () target Sugerencia, le muestra la firma de los métodos C# que puede usar. El compilador C# traduce la representación C# a IL. La implementación de IL se verá diferente, porque IL no es un lenguaje de estilo C, y el compilador C# proporciona azúcar sintáctica para abstraer los detalles de implementación.

Esto es solo una suposición, así que no me dispares si me equivoco, pero creo que IntelliSense está obteniendo la firma del método objetivo del Invoke Método definido en el delegado. El reflector muestra claramente que el Invoke método sobre System.Action<T> es:

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

Que es lo mismo que la sugerencia de firma ofrecida por Intellisense. La magia es IntelliSense, al ver un tipo delegado, mira el Invoke Método y sugiere un constructor que toma un objetivo que lo coincida.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top