C sharp NET/Capítulo 13
Delegación y Eventos
editar
Programando con delegados
editarOtra cuestión a tener en cuenta cuando programemos con delegados, es que éstos no tienen en cuenta la visibilidad de los métodos. Esto permite llamar a métodos privados desde otros si ambos tienen acceso al delegado. Es decir, imaginemos que una clase guarda en un delegado referencia a uno de sus métodos privados. Si desde otra clase que tenga acceso al delegado (pero no al método privado) se convoca a éste, se ejecutará ese método. En verdad no se está violando la privacidad del método, porque no es la clase quien lo convoca, sino el delegado, que sí tiene acceso al mismo.
Llamadas a múltiples métodos
editarHasta el momento hemos visto como hacer que un delegado guarde referencia de un sólo método. Sin embargo, existe una clase, System.MulticastDelegate, que deriva de System.Delegate, que se diferencia de esta última en que puede tener múltiples métodos en su lista de invocaciones. Al usar la palabra clave "delegate" se están usando estas clases de forma interna, sin tener que hacer referencia a ellas en el código.
Para poder hacer esto usaremos los operadores sobrecargados '+=' y '-=' que, respectivamente, añaden o eliminan a un método de la lista de invocaciones de un delegado.
Para intentar asimilar esto mejor, veámoslo con un ejemplo más completo.
Ejemplo de uso de delegados
editarusing System; // Define el tipo delegado delegate void MiDelegado (string cadena); class Ejemplo { public static MiDelegado delegado; public static void Main () { // Crea una un objeto delegado y le asigna un método. delegado = new MiDelegado (ClaseA.MetodoEstatico); ClaseA A = new ClaseA(); delegado += new MiDelegado (A.MetodoPublico); ClaseB B = new ClaseB(); // El constructor inserta MetodoPrivado // delegado += new MiDelegado (B.MetodoNoValido); // Excepción // el método no cumple con la definición del tipo delegado delegado ("Hola mundo"); } } class ClaseA { public static void MetodoEstatico (string cad) { Console.WriteLine ("ClaseA.MetodoEstatico ha sido llamado: {0}", cad); } public void MetodoPublico (string cad) { Console.WriteLine ("ClaseA.MetodoPublico ha sido llamado: {0}", cad); } } class ClaseB { void MetodoPrivado (string cad) { Console.WriteLine ("ClaseB.MetodoPrivado ha sido llamado: {0}", cad); } public void MetodoNoValido (int entero) { Console.WriteLine ("ClaseB.MetodoNoValido ha sido llamado: {0}", entero); } public ClaseB () { Ejemplo.delegado += new MiDelegado (MetodoPrivado); } }
Podemos ver que, en este caso, nuestro delegado sólo manipula métodos que no devuelvan nada y que reciban como único parámetro una cadena. Si observamos los métodos que componen ClaseA y ClaseB, el denominado MetodoNoValido no concuerda con la definición de nuestro delegado, ya que recibe un entero y no una cadena. Eso implica que no vamos a poder llamarlo desde ninguna instancia del delegado que hemos declarado. Sin embargo, con las otras no tendremos ningún problema.
Bien, observemos paso a paso lo que hace el programa. Fijemos nuestra atención en el método principal (Main). Primero insertamos un método estático. Como sabemos, para llamar a un método de este tipo, se hace a partir del nombre de la clase y no de una instancia. Bien, hasta aquí nada que no hayamos visto ya, pero ahora insertemos un segundo módulo en el delegado.
Como hemos dicho, hemos usado el operador '+=' para incluir otro método más en nuestro delegado, en este caso MetodoPublico. Si usaramos de nuevo el operador '=', borraríamos la antigua lista de invocaciones y crearíamos una nueva con sólo una función referenciada. Ahora tenemos dos métodos en la lista de invocaciones de nuestro delegado. Por último, creamos una instancia de ClaseB, la cual en su constructor incluye una referencia más al delegado, en este caso a MetodoPrivado.
Si ahora compilamos y ejecutamos este código, obtendremos esto:
ClaseA.MetodoEstatico ha sido llamado: Hola mundo
ClaseA.MetodoPublico ha sido llamado: Hola mundo
ClaseB.MetodoPrivado ha sido llamado: Hola mundo
Como vemos, aunque hemos convocado al delegado desde la clase Ejemplo, que no tiene acceso a MetodoPrivado, éste ha sido ejecutado. Como explicamos, esto es así porque realmente quien lo está haciendo es el delegado y no el método Main.
Por último, una cuestión más. Hasta el momento hemos visto a delegados que gestionan miembros que no devuelven ningún valor. Pero, ¿qué ocurre cuando los devuelven? En este caso, la ejecución del delegado no devuelve todos esos valores, sólo el que retorne el último método de su lista de invocación.