2012-02-25 11 views
11

He leído que un tipo de referencia contiene la referencia a un objeto real que puede almacenarse en el montón administrado. Cuando un método se "asigna" a una variable de referencia de delegado, ¿a qué memoria apunta la referencia? ¿Qué tiene que ver este bloque de memoria con el código de función real?¿Qué señala un delegado?

+0

No es exactamente la respuesta que está buscando, pero esta publicación podría proporcionar alguna información sobre los delegados http://stackoverflow.com/questions/527489/how-delegates-work-in-the-background –

Respuesta

14

Tomemos un ejemplo sencillo aparte:

using System; 
class Program 
{ 
    delegate bool MyFilter(int x); 

    bool IsOdd(int x) 
    { 
     return x % 2 == 1; 
    } 

    static void Main() 
    { 
     MyFilter f = new Program().IsOdd; 
     Console.WriteLine(f(5)); 
    } 
} 

¿Qué hace el compilador? Vamos a empezar con esta línea:

delegate bool MyFilter(int x); 

El compilador genera un tipo que se ve algo como esto:

class MyFilter : MulticastDelegate 
{ 
    public MyFilter(Object thisRef, IntPtr method); 
    public bool Invoke(int x); 
    // BeginInvoke(), EndInvoke() - Let's ignore those 
}  

El tipo myFilter tiene un constructor que acepta dos parámetros: un IntPtr que el cuerpo del método invocar, y un Objeto sobre el cual este método debería ser invocado. El método Invoke() en el tipo de MyFilter invoca al delegado real.

Ahora, veamos qué sucede en el método Main(). El compilador reescribirla algo como esto:

static void Main() 
    { 
     MyFilter f = new MyFilter(new Program(), addressof(Program.IsOdd)); 
     Console.WriteLine(f.Invoke(5)); 
    } 

Por supuesto, AddressOf no es un operador real C#, pero se puede imaginar que devuelve la dirección del cuerpo para el método pasado de entrada. Además, no discutí otros temas relacionados con los delegados, como el encadenamiento (esta es una característica proporcionada por la clase base de MulticastDelegate), pero espero haber abordado su pregunta.

Para resumir, la referencia de delegado apunta a un objeto que implementa un método Invoke que coincide con la firma del delegado. El objeto rastrea el puntero al método que necesita invocarse, y también el objeto de destino en el que invocar el método (a menos que el método sea estático).

0

En realidad, hay dos tipos de delegados, Delegate y MulticastDelegate. Estas son clases abstractas heredadas en una instancia real de delegate. Recomendaría leer estas clases ya que tienen muchos más detalles (precisos) de los que he explicado aquí, pero para la versión corta:

Si bien no estoy 100% seguro de cómo funciona exactamente la implementación, la forma más fácil de pensar en un objeto Delegate tiene un object y MethodInfo, que es el tipo de reflejo para un método en particular. La razón por la cual el tipo Delegate es abstracto es porque el método Invoke depende de los parámetros del método.

mismo modo, MulticastDelegate contener múltiples Delegate objetos, que cada punto a un individuo combinación object/MethodInfo. Esto permite que el sistema event, donde se dispara un solo event se llame a múltiples métodos.

Volviendo a los detalles de implementación, cuando se define un delegado, se crea una clase heredada de MulticastDelegate con un método Invoke, también la object puede haber null para los métodos estáticos.

Además de esto, usted tiene los detalles sobre cómo pasan los objetos MulticastDelegate entre las invocaciones, pero probablemente ya cometí algunos errores en esta publicación, así que lo dejo así.

0

Sin dar una respuesta demasiado complicada, apunta (hace referencia) al bloque de memoria real donde se almacena el método.

0

Un delegado realmente contiene dos direcciones: la dirección del método y la dirección del objeto. Esto es bastante interesante, y varias patentes relacionadas con delegados fueron otorgadas a Heljsberg http://www.google.com/patents/US6185728

Es altamente eficiente. En un interview, Heljsberg señaló que puede ser más eficiente que el envío VTBL (ya que es un puntero directo a una función). En los casos más simples, es literalmente una llamada indirecta. por ejemplo,

jmp *%eax 

En general, se necesita 4 instructions to execute a delegate.

Cuestiones relacionadas