Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Un delegado es un tipo que encapsula de forma segura un método, similar a un puntero de función en C y C++. A diferencia de los punteros de función de C, los delegados están orientados a objetos, proporcionan seguridad de tipos y son seguros. En el ejemplo siguiente se declara un delegado denominado Callback
que puede encapsular un método que toma una cadena como argumento y devuelve void:
public delegate void Callback(string message);
Normalmente, un objeto delegado se construye proporcionando el nombre del método que el delegado envuelve o con una expresión lambda. Un delegado se puede invocar una vez creada una instancia de esta manera. Al invocar un delegado, se llama al método asociado a la instancia del delegado. Los parámetros que el invocador pasa al delegado se transmiten al método. El delegado devuelve, si lo hay, el valor de retorno del método. Por ejemplo:
// Create a method for a delegate.
public static void DelegateMethod(string message)
{
Console.WriteLine(message);
}
// Instantiate the delegate.
Callback handler = DelegateMethod;
// Call the delegate.
handler("Hello World");
Los tipos delegados se derivan de la Delegate clase en .NET. Los tipos delegados están sellados, no se pueden derivar de y no es posible derivar clases personalizadas de Delegate. Dado que el delegado con instancias es un objeto, puede pasarse como argumento o asignarse a una propiedad. Un método puede aceptar un delegado como parámetro y llamar al delegado en algún momento posterior. Esto se conoce como devolución de llamada asincrónica y es un método común para notificar al llamador cuando finaliza un proceso largo. Cuando se usa un delegado de esta manera, el código que usa el delegado no necesita ningún conocimiento de la implementación del método que se está usando. La funcionalidad es similar a la que proporcionan las interfaces de encapsulación.
Otro uso común de devoluciones de llamada es definir un método de comparación personalizado y pasar ese delegado a un método de ordenación. Permite que el código del autor de la llamada forme parte del algoritmo de ordenación. El método de ejemplo siguiente usa el Del
tipo como parámetro:
public static void MethodWithCallback(int param1, int param2, Callback callback)
{
callback("The number is: " + (param1 + param2).ToString());
}
A continuación, puede pasar el delegado creado en el ejemplo anterior a ese método:
MethodWithCallback(1, 2, handler);
Y recibir los siguientes resultados en la consola:
The number is: 3
MethodWithCallback
no necesita llamar directamente a la consola, ya que no tiene que diseñarse teniendo en cuenta una consola. Lo que MethodWithCallback
hace es preparar una cadena y pasar la cadena a otro método. Un método delegado puede usar cualquier número de parámetros.
Cuando se construye un delegado para encapsular un método de instancia, el delegado hace referencia tanto a la instancia como al método . Un delegado no tiene conocimiento del tipo de instancia aparte del método que encapsula. Un delegado puede hacer referencia a cualquier tipo de objeto siempre que haya un método en ese objeto que coincida con la firma del delegado. Cuando se construye un delegado para encapsular un método estático, solo hace referencia al método . Tenga en cuenta las siguientes declaraciones:
public class MethodClass
{
public void Method1(string message) { }
public void Method2(string message) { }
}
Junto con el DelegateMethod
estático mostrado anteriormente, ahora tenemos tres métodos que puede envolver en una instancia Del
.
Un delegado puede llamar a más de un método cuando se invoca, denominado multidifusión. Para agregar un método adicional a la lista de métodos del delegado —la lista de invocación—, simplemente es necesario agregar dos delegados mediante los operadores de adición o asignación y suma ('+' o '+='). Por ejemplo:
var obj = new MethodClass();
Callback d1 = obj.Method1;
Callback d2 = obj.Method2;
Callback d3 = DelegateMethod;
//Both types of assignment are valid.
Callback allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;
allMethodsDelegate
Contiene tres métodos en su lista de invocación:Method1
, Method2
y DelegateMethod
. Los tres delegados originales, d1
, d2
y d3
, permanecen sin cambios. Cuando allMethodsDelegate
se invoca, se llama a los tres métodos en orden. Si el delegado usa parámetros de referencia, la referencia se pasa secuencialmente a cada uno de los tres métodos a su vez, y los cambios realizados por un método son visibles para el método siguiente. Cuando cualquiera de los métodos produce una excepción que no se detecta en el método, esa excepción se propaga al autor de la llamada del delegado. No se llama a ningún método posterior de la lista de invocación. Si el delegado tiene un valor devuelto o los parámetros de salida, devuelve el valor devuelto y los parámetros del último método invocado. Para quitar un método de la lista de invocación, use los operadores de sustracción o de asignación de sustracción (-
o -=
). Por ejemplo:
//remove Method1
allMethodsDelegate -= d1;
// copy AllMethodsDelegate while removing d2
Callback oneMethodDelegate = (allMethodsDelegate - d2)!;
Dado que los tipos de delegado se derivan de System.Delegate
, los métodos y propiedades definidas por esa clase se pueden llamar en el delegado. Por ejemplo, para buscar el número de métodos en la lista de invocación de un delegado, puede escribir:
int invocationCount = d1.GetInvocationList().GetLength(0);
Los delegados con más de un método en su lista de invocación derivan de MulticastDelegate, que es una subclase de System.Delegate
. El código anterior funciona en cualquier caso porque ambas clases admiten GetInvocationList
.
Los delegados de multidifusión se utilizan mucho en el control de eventos. Los objetos de origen de eventos envían notificaciones de eventos a los objetos de destinatario que se registraron para recibir ese evento. Para registrarse para un evento, el destinatario crea un método diseñado para controlar el evento y, a continuación, crea un delegado para ese método y pasa el delegado al origen del evento. El origen llama al delegado cuando se produce el evento. Después, el delegado llama al método que controla los eventos en el destinatario y entrega los datos del evento. El origen del evento define el tipo de delegado para un evento determinado. Para obtener más información, consulte Eventos.
Comparar delegados de dos tipos diferentes asignados en tiempo de compilación produce un error de compilación. Si las instancias del delegado son estáticamente del tipo System.Delegate
, se permite la comparación, pero devuelve false en tiempo de ejecución. Por ejemplo:
delegate void Callback1();
delegate void Callback2();
static void method(Callback1 d, Callback2 e, System.Delegate f)
{
// Compile-time error.
Console.WriteLine(d == e);
// OK at compile-time. False if the run-time type of f
// is not the same as that of d.
Console.WriteLine(d == f);
}