You are on page 1of 6

dnm.inicio.

fundamentos
dnm.incio.fundamentos

Guillermo “Guille” Som

Delegados y eventos
Primera parte: ¿En quién delegas tú?

En este número vamos a tratar de los delegados, y también de los eventos (aunque de
estos últimos nos encargaremos con más detalle en el próximo artículo), ya que en
.NET están estrechamente relacionados;tanto es así que no podemos definir un even-
to sin la intervención de un delegado.

<< Delegados y eventos en Visual Basic y C# En este caso, primero se define un delegado y a
continuación hay que definir el evento que debe ser
Seguramente los programadores de Visual Basic del tipo de ese delegado. Complicado, ¿verdad? Ahora
estarán pensando que lo dicho en la entradilla no es mismo no entraremos en muchos detalles sobre esto,
totalmente cierto. Bueno, posiblemente no, porque antes veamos cómo se lanzaría ese evento tanto des-
si están leyendo dotNetManía sabrán lo que se escon- de Visual Basic como desde C#:
de tras los eventos. Pero no está de más aclararlo para
' En Visual Basic:
que no queden dudas. RaiseEvent Click(sender, e)
Lo cierto es que Visual Basic es un lenguaje muy
protector, y nos “libera” de ciertas tareas para facili- // En C#:
tarnos el trabajo real, de forma que nos podamos con- if( Click != null )
{
centrar en lo que de verdad importa y olvidarnos un Click(sender, e);
poco de ciertos “asuntillos” que en parte solo nos }
hacen teclear más.
Aclaremos un poco todo esto que acabo de comen-
tar. En Visual Basic, para definir un evento solo hay que Indudablemente en Visual Basic sigue siendo mucho
escribir la instrucción Event seguida de la definición que más fácil, más simple, menos complicado, no tenemos
daremos al método que recibirá los eventos. Por ejem- que comprobar nada... Y es cierto, a eso es a lo que me
plo, si nuestra clase es del tipo Button, podemos definir refería con lo de que Visual Basic es muy “protector” y
el evento Click de la siguiente forma: nos libera de ciertos detalles que en realidad no nece-
sitamos saber, o al menos, no es obligatorio que sepa-
Public Event Click( ByVal sender As Object,_
ByVal e As EventArgs )
mos. Por otra parte a los programadores de C#, segu-
ramente por aquello de que les gusta “escribir más”
código, pues... ¡que escriban más! Aunque, como vere-
Guillermo “Guille” Som Como podemos comprobar, esa es la definición mos en este artículo, eso ya está cambiando, y ahora
es Microsoft MVP de Visual Basic
desde 1997. Es redactor de
que usaremos en cualquier formulario que quiera podrán hacer también ciertas cosas sin necesidad de
dotNetManía, miembro de Ineta interceptar la pulsación en un botón. Simple, ¿ver- escribir tanto, ya que el propio compilador de C# se
Speakers Bureau Latin America, dad? Veamos ahora cómo tendría que definir ese mis- encargará de algunos aspectos, digamos, de trasfondo.
mentor de Solid Quality Learning mo evento un programador de C#: Pero al final, tanto C# como Visual Basic deben seguir
Iberoamérica y autor del libro
Manual Imprescindible de
las reglas de .NET, y aunque nosotros como usuarios
public delegate void ClickEventHandler(
Visual Basic .NET. object sender, EventArgs e);
no tengamos que preocuparnos, los compiladores sí que
http://www.elguille.info public event ClickEventHandler Click; lo harán.

si queremos acceder a todo esto los lenguajes adscritos a . Y los delegados no son en cierto modo similar a las interfaces (ver devolver un valor de tipo String. simplemente estarán preparados y sabrán soportar el cambio. acceso indebido a la memoria.NET no le gustan las que algunas veces el que nos “mimen” sas de .NET son.fundamentos Independientemente de las bromas.NET es prototipo en el que indiquemos de qué posiblemente se nos pueda presentar a más estricto y menos permisivo para estas tipo es ese método. . mente causado por un acceso a una posi..NET no permitirá la ejecución del gado permite acceder a una función de debemos definir un delegado con esas código. es decir. no está de más que algunos puntos estén totalmente claros. se caracteriza por ser un entorno de te del nombre que cada compilador le Esa definición del prototipo de fun- código administrado (managed code) o lo dé.NET no le gustan los tipos definidos en la librería de cla. y cuando posteriormente .NET controla. por eso impone reglas que tanto no es bueno. a . dirección de memoria de dicha función Pero como siempre hay gente nue- va. arbitrario. Y sabiendo la dirección de hacerlo directamente o por medio de <<dotNetManía re decir que no podamos hacer cosas que de memoria. Una vez que tenemos definidos debemos seguir sus normas. tenemos que hacerlo por medio lo dedicado a los delegados y a los even. y que esos métodos anóni- mos los podrán crear donde se pueda usar un delegado. ya que nos acostum. pero si lo hacemos. método. lo que también se conoce como un una función que devuelve una cadena y deben respetarlo. del tipo definido por el delegado. permita acceder a esa función. o que ya no es nece- sario usar un constructor para crear un tipo delegado o que por medio de la Un delegado permite acceder a una función de covarianza o la contravarianza podrán usar de forma más óptima los delega- forma casi anónima. ya que de no ser así. “está por allí” y revisa que en realidad debemos cumplir.. usaremos un objeto .NET que nos serie de tipos de datos. si no. y la forma de tos. como los programadores de Visual Basic) de con C#. es cuando ¿Qué son y para qué sirven los Como sabemos.inicio. Si una función tiene que ses. en lugar está bajo su influencia. Y esto es aplicable a todo lo que forma casi anónima. ción de memoria que no estaba dentro del controlar ese acceso es definiendo un mos por aclarar casi cualquier duda que rango que teníamos permitido. De lado. Pero en . de forma que ese acceso no sea nos lleva a una segunda definición de lo 43 . ¿por anteriormente. ya he dicho. . Aunque en todas las puertas fal. Y delegado es una referencia a una fun.ya que simplemente tiene la dos.NET ción. accediendo al sitio correcto. nos dicen que si queremos usar la nue. terminare. Sabiendo esto. a . los cuales pode. las versiones anteriores de Windows. de la memoria o del tos. Podemos pensar que un delegado es devolver un valor de tipo String. que no nos “cole- tenemos que ser conscientes (sobre todo llado con C. . además de qué aparecen los fallos de protección seguridad y la única forma de tenerla es que también debemos saber en qué general? (las típicas pantallas azules de creando normas de conducta y de utili- medida están relacionados con los even.NET define una le decimos al runtime de . que están las definiciones de los méto- ra les dicen que pueden crear métodos dro de diálogo más “mono”). y por error deja seguir. podrá controlar que estamos Como sabemos. (tanto en C# como en Visual Basic). Esto a los programadores de C# no que ahora simplemente están remoza. << dnm. bajo el abrigo de la seguridad de . si las cumplimos. Y esto es así por todo lo comentado va instrucción Custom Event debemos mos crear grandes problemas. si recibe paráme- la hora de trabajar con los eventos y con cuestiones. de un puntero controlado. no nos va a ser sencillo. bran mal. y de hacerlo cuántos y de qué tipo los delegados. si aho. Así. ya que independientemen. que como sabemos método debe recibir dos parámetros de Pero. si queremos estar tros. .. si no las cumplimos. características. pode.. o mejor dicho. un puntero directo. todos estos requerimientos. forma. das y han cambiado de look por un cua. Lo que no quie. llega la versión 2005 y en otros lenguajes no es así. debe comunes (CTS). De esta delegados? mos usar indistintamente desde un len. un dele. zación. en este caso. a todo lo que te tiene la dirección de memoria de queramos acceder a ese método. en el sistema de tipos do. por tanto. Lo que debemos hacerlo por la puerta falsa. y cuando creemos que todo no hagamos demasiadas trastadas. o porque así lo hayamos previsto. si queremos acceder a un vamos a intentar en este primer artícu. que recibe un parámetro de tipo Cliente. ya que simplemen. Y en los que seguirán. der lo hacemos por medio de un delega- las sorpresas. Esto pasamos. dos o funciones. ya que el CLR quiere saber manejar los delegados. es decir. si un una excepción. en realidad estamos trabajando con ción (o método) al que queremos acce- que es lo mismo. acceso a esas partes de la memoria en la les pillaría tan desprevenidos. es decir. así que eso es lo que Este tipo de problema se debe a un Por tanto.NET no permita. normal.NET siempre hay alguien que sorpresas. puntero a una función. dicha función. incluso los que desarrollan mos” donde no debemos. eso es lo que recibirá.NET Framework guaje u otro. ¿qué es un delegado? Un definen un contrato que debemos respe- tipo Object. esto saben mucho los que han desarro. tar. podemos acceder a ella. anónimos.NET esto debe estar contro. dotNetManía nº 16). ya que.

pasando como argumento tas circunstancias no tenemos una for. gado. que si la tuviéramos. pues no necesitamos usar un dele. En este caso.MiFuncion). tenemos un método que define un parámetro del tipo del delega- do. deberíamos tener “cercana” la función a Fuente 2. es Es decir.. ¿cómo se o en otra. Pero si quisiéramos acceder MiFuncion. Es más. Veamos el siguiente código y segu- ro que esa cercanía no es tan necesaria: Los delegados definen la “firma” que los métodos public static void usarMiFuncionDelegado( MiFuncionDelegado mfd) { a los que queremos acceder deben tener } string s = mfd( new Cliente() ). con la diferencia de que en { el constructor debemos indicarle la fun. Esto es definido. un código muy parecido al usado ante. string s = mfd( new Cliente() ). sino el del objeto creado a tramos anteriormente en el que usába- ríamos la forma directa mostrada ante. sin importar e igualmente comprensible. que como vemos. static void Main(string[] args) cualquier tipo. de un constructor. podemos usar un delegado podríamos hacerlo? porque para poder y por medio de dicho delegado acceder definir una variable como en este caso. tancia de la clase que lo define. Primero defi. MiFuncionDelegado mfd = MiFuncion.} tienen porqué estar todas defi- nidas en una misma clase. simplemente esta. no tendríamos en este código no usamos el nombre de De igual forma. por tanto. do y no importará donde estén definidos.inicio. debido a que no esta. MiFuncionDelegado(c. mos acceder: ni el método ni la función a la que acce- Veamos el ejemplo del método que deremos por medio del delega- devuelve una cadena y recibe un paráme. {return “. Que como podemos comprobar. ¿Por qué tanta complicación? Porque debemos suponer que en cier. desde donde hagamos la llama- mos definir en C# de esta forma: da. La única condición es que tro de tipo Cliente. también estamos acce. Por supuesto aquí no estamos usan. do pasándole la dirección de una función decir que es un tipo especial que nos per.<< dnm. podemos llamar a ese méto- que es un delegado. el código que mos- necesidad de complicarnos la vida y usa. Para acceder a esa función por hacerlo en las versiones anteriores sería nición y solo tendríamos que indicar medio del delegado que acabamos de esta otra: dónde está definido para permitirnos el crear. nimos el delegado usando la misma “fir. ción a la que queremos acceder: usarMiFuncionDelegado(c. sin necesidad de usar una ins. es más simple pueda acceder a ese método sin necesi. ya riormente. y la forma en que tendríamos que definir un delegado que tenga esa defi. En este caso. dad de saber si está definido en una cla. Debemos notar en la forma en que mos indicando dónde está dicha fun. y como los delegados Para acceder a este método lo pode- algo así: en realidad son como clases. do ningún puntero. directa.. Ese método lo pode. <<dotNetManía al método. método de cualquier clase. que cumpla con la definición del delega- mite definir la forma de acceder a una ma” que tiene el método al que quere.0 permite asignar Veamos la definición del delegado la que queremos acceder. definimos una siquiera en un mismo ensamblado! La forma de usar ese método sería variable de ese tipo. do. } MiFuncionDelegado mfd = new mos accediendo a ese método de forma MiFuncionDelegado(MiFuncion).fundamentos gado. podríamos tener las cosas simples. Y si la tenemos directamente la función sin necesidad que nos permitiría acceder a esa función cerca.”. ¡ni Para usar el delegado. cómo y dónde se haya definido. pero lo dejamos así para man. llamamos al método que recibe el dele- ción. pero no public string MiFuncion(Cliente c) método definido con la misma firma.0 (aunque no en Visual de una forma más anónima.MiFuncion)). función. en la que podemos y cómo podemos usarlo. Basic). un objeto creado a partir del “tipo” del ma directa de acceder a ese método. nuevo en C# 2. partir del delegado. lo haremos así: usarMiFuncionDelegado(new acceso. ya que simplemente le hemos do desde la propia clase en la que está diendo desde la propia clase al método pasado el nombre de la función. podemos usar mos hacer de esta forma: el mismo código que usamos para crear string s = MiFuncion( new Cliente() ). suponemos que estamos accedien. Definición de un delegado para acceder a un métodos (o funciones). la función. C# 2. 44 . mos también un constructor de ese tipo riormente. Por ejemplo. public delegate string MiFuncionDelegado(Cliente c). si queremos Ahora supongamos que este último lo podríamos haber escrito de esta otra que desde otra parte del código alguien código lo queremos usar en cualquier forma. Cliente c = new Cliente(). tengamos acceso a ambos Fuente 1. pero con la diferencia de que delegado.

Debido a string s = mfd(new Cliente()). tas. En el código nas otras características de los delega. pero al que finalmente las utilizan los eventos. no viene mal darles un repaso. Usos prácticos de los delega. es decir. Algunos de los usos que vamos a ver son string s = mfd(new Cliente(“Pepe”)).WriteLine(s). De hecho. void usaMiFuncion2(){ } tratado en otros números de esta revista. {return “Hola “ + c. las dos formas de realizar la asignación mfd = New MiFuncionDelegado(AddressOf MiFuncion) mos temas que son y en el fuente 4 vemos el código IL que Dim mfd As MiFuncionDelegado = AddressOf MiFuncion específicos de Visual crea el compilador. Fuente 5. exclusivos de C# 2. pasamos como parámetro del construc. comprueba el tipo de la variable que reci. evento con un código. El código IL es el mismo para las dos formas MiFuncionDelegado(AddressOf c.Nombre.}. En En el código del fuente 3 tenemos Dim mfd As MiFuncionDelegado otro artículo tratare. (al igual que ocurre con newobj instance void Cliente::.0. el cual es exactamen- Basic y por consi. cionamiento de los delegados. te el mismo en ambos casos. o en la forma tor la función a la que queremos apuntar. para comprender mejor cómo funcionan nadas con los delegados. será el propio compilador el que haga el uso adecuado dos del delegado correspondiente. delegado en cualquier sitio que el com- der a esos métodos por medio de instan. el Fuente 3.MiFuncion) usarMiFuncionDelegado(New Fuente 4. en cuyo caso. en este caso no quedan cosas que explicar que también string s = mfd(new Cliente()). sin tos.MiFuncion)) mostradas en el fuente 3.0 el compilador se pue- los delegados El ejemplo más claro del uso de los de encargar de averiguar qué delegado es En la versión 2. ya que como Métodos anónimos pasando es la dirección de memoria de comenté anteriormente los delegados son la función. vamos a ver el compilador será el mismo en los dos mfd = delegate(Cliente c) en qué situaciones podemos usarlos. En las asignaciones también podemos usar cualquiera de las dos formas: exclusiva para C#. pero lo importante es ver cómo se 45 .1 ret usarMiFuncionDelegado(AddressOf c. el compilador diente podemos escribir en el cuerpo de para trabajar con los eventos. esa exclusividad de uso en C#. Las dos formas equivalentes de te el saludo. aunque } que sería más fácil mostrar directamen- (como es costumbre en esta sección). casos. tal como hemos visto en el código del definirlo nosotros de forma indepen- pero que no necesariamente usaremos fuente 2. vamos a verlo con el código que esta- esto con los eventos. public static void usaMiFuncion4() Para que nos quede más claro el fun. ya <<dotNetManía son válidas para ese lenguaje. y aunque ya se han Console. necesidad de que tengamos que crear una mos usando últimamente. pero como aún transparente para nosotros. instancia de la clase del delegado al que le del fuente 5 podemos ver cómo crear un dos que en el fondo también están rela. ro 20 de esta revista) podemos usar los no hemos tratado con detalle los even- Antes de ver qué relación tiene todo delegados de forma directa.inicio. en lugar de dar tantas vuel- código mostrado será prácticamente en asignar el puntero a una función. repasaremos algu. delegado. y debe. decirle a } void usaMiFuncion3(){ los lectores que prefieren Visual Basic que MiFuncionDelegado mfd = new no pasen al siguiente artículo. Novedades de C# respecto a pilador esperaría que se asignara un cias creadas a partir del delegado.0 de C# (tal como métodos anónimos es para relacionar un el que debe usarse y lo usará de forma explicó Octavio Hernández en el núme.ctor() C# 2.ctor(object. Y es que en C# ma” que los métodos a los que queremos los eventos.native int) formas que acabamos de ver. << dnm.la forma de acceder a una función siempre es por medio ldftn instance string Cliente::MiFuncion(class Cliente) de la instrucción AddressOf y la podemos usar también de las dos newobj instance void MiFuncionDelegado::. veniente. una pieza clave para los eventos. ma firma que la función. MiFuncionDelegado mfd = MiFuncion.0). será el propio compilador el que determinará si esa función callvirt instance string MiFuncionDelegado::Invoke(class Cliente) cumple o no los requisitos del parámetro que espera el método: stloc. la función anónima lo que creamos con- be el puntero a la función y si tiene la mis. hace falta usar un método anónimo. 2. mos usando C# 2.0 del delegado o de forma directa. En esos casos.0 podemos usar una definición de un acceder deben tener. Los métodos anónimos son otra de De todo lo que hemos visto debemos mos saber cómo funcionan los delegados las novedades de C# que están relacio- concluir que los delegados definen la “fir. es decir por medio de un objeto del tipo stloc. el delegado MiFuncionDelegado. Definición de un método anónimo. y que podemos acce. lo que estamos go será en ese lenguaje.fundamentos NOTA En Visual Basic. Como es evidente. método anónimo con la misma firma que cionadas con los eventos. y si esta. si examinamos el código IL generado por { MiFuncionDelegado mfd. ya que aún MiFuncionDelegado(MiFuncion).0 ldloc. guiente todo el códi- En cualquier caso.

la documentación nos dice mayor utilidad con los eventos o cuando queramos que: Cuando un método delegado tiene un tipo de valor simplemente definir la función “apuntada” de forma devuelto que es más derivado que la firma de delegado.WriteLine(s). visto. string saludo){ return saludo + “ “ + c. ción. hacer una conversión (cast) ya que el valor devuelto por el delegado es del tipo Persona. tiene que esto solo lo podemos hacer con C#. fuente. devuelve un objeto del tipo Persona: usarMiFuncionDelegado(c. definición de una clase Persona y un delegado que devuelve un valor de ese tipo: mfd = delegate(Cliente c. // Omitidas las asignaciones a las propiedades Fuente 6. mismo teníamos que definir un delegado para cada ramente para gente más experta que yo en C#. Console. public delegate Persona PersonaCallback(). ese método se denomina con- no sabes el tacto que tiene. Colega unColega = (Colega)nColega(). que devuelve un objeto de ese mismo tipo: mo ámbito que el método o propiedad que contie- public class Colega : Persona ne esa definición anónima.Nombre. ya que como hemos visto anteriormente. return new Colega(). independiente- mente del tipo que devuelva en realidad la función a Covarianza y contravarianza la que hace referencia ese delegado. Lo que viene a significar que los tipos de 46 . en realidad no es un } método. En realidad. de los parámetros de método. // Omitida la definición de la propiedad Correo flicto entre la variable definida directamente y la defi- } nida como parámetro del método anónimo. lo lógico era que me empapara del la contravarianza: Cuando una firma de método delegado <<dotNetManía tema. lo que no nos estará permitido mos que esto significa que podemos usar delegados hacer es modificar la firma del delegado. se directa. por tanto. El ámbito de un método anónimo es el mismo que En la asignación a la variable unColega debemos el del bloque en el que se define. Podemos usar esa función como el método al que apuntará el delegado PersonaCallback.inicio. Y como una de los tipos que quisiéramos devolver. en Visual pués de leer la descripción de la ayuda de Visual Studio Basic no está permitida esta forma de usar los valores 2005 pensé en la suerte que tenía de que mi lenguaje devueltos por un delegado.Nombre. que como hemos Cliente c = new Cliente(). tal como vemos en el siguiente código otra clase derivada. des. Pero si iba a hablar de esto Veamos ahora qué nos dice la documentación sobre en este artículo. de ser cualquier clase de ese mismo tipo o de cualquier tro a la función. La primera vez que leí estas dos palabras. } En el código del fuente 6 podemos ver ese con. al leerlo sabiendo variable que apunta al método la podemos pasar como qué es lo que significa no era tan rebuscada la defini- argumento a otro método. el compilador nos avisará (entre otras cosas). esa denomina covariante. dire- En cualquier caso. hasta que no lo tienes entre las manos. PersonaCallback nColega. en el siguiente código. Pero para dejarlo en un lenguaje más llano. para conseguir esto que el tema tratado debía ser muy complicado. mos Colega. Ni que decir soy un catetillo de pueblo que no tiene estudios.}. tenemos la MiFuncionDelegado no tiene dos argumentos. que Por ejemplo. materno no fuese el C#. }. y la varia. segu. travariante. pensé En las versiones anteriores.NuevoColega. public class Persona { Es importante saber que aunque estemos decla. en la que definimos un método estático ble definida en el parámetro también tendrá el mis. los cuales tienen Sobre la covarianza. // Omitidas las definiciones // de las propiedades Nombre y Apellidos rando un “método” anónimo. al menos en el sentido de los ámbitos o cobertura de las variables.MiFuncion). mfd = delegate(Cliente c) {return “Hola “ + c. MiFuncionDelegado mfd. Debemos pensar en que { el cuerpo del método anónimo en realidad es como public static Colega NuevoColega() cualquier otro bloque de código que podamos { incluir dentro de un par de llaves. Y con esto pasa como tiene uno o más parámetros de tipos que derivan de los tipos con casi todo. a la que llamare- que hayamos declarado anteriormente.fundamentos pueden usar los métodos anónimos. al menos si lo iba a tratar. string s = mfd(new Cliente(“Manolo”)). nColega = Colega. si se que devuelvan un tipo y el receptor de ese valor pue- nos ocurre la brillante idea de añadir un nuevo paráme. ya que desde ese méto- do anónimo podemos acceder a cualquier variable Y definimos una clase derivada.<< dnm.

otra característica interesante de los delegados: la dor (realmente el runtime) usará la clase que corres. (como casi todo lo relacionado con los delegados). a pesar de ser menos espe- Fuente 7. Pero el uso más práctico de esta característica será se hemos definido un constructor que recibe como pará. Por ejem- public Cliente() { } plo. en el sitio string sco = mfd2(co). si queremos esa funcionalidad en Conclusiones las dos clases. por tanto. Web de dotNetManía está disponible el código de Console. el evento KeyPress recibe un parámetro del tipo public Cliente(string nombre) KeyPressEventArgs. lo permitirá. el parámetro en la definición nido en el delegado (así era hasta la versión 2. simplemente por- Incluso podemos crear un método anónimo que que aquél no soporta algunas de las características de use un objeto del tipo ClienteOro como parámetro. Cuando utilizamos los métodos de eventos de los controles de Windows Forms. aunque en el caso de Visual <<dotNetManía Basic no será equivalente al de C#. Pero la razón de que lo hayamos teni- do que hacer en las dos clases es porque los constructores no se heredan. co2.. public class Cliente { pero dependiendo del evento.WriteLine(mfd3(co)). de esa forma nuestro código de ejem. tipo exacto. pero será en el próximo artículo donde veremos ba un delegado que apunte a MiFuncion y el compila. ese parámetro será del // Omitida la definición de la propiedad Nombre tipo adecuado para el evento en cuestión. tiene C#. } KeyPressEventArgs e) { . Cliente o derivado: Siguiendo con el ejemplo del delegado que recibe MiFuncionDelegado mfd3.}. En el fuente 7 vemos esas dos cuando lo apliquemos a los eventos.. cretos y siempre que necesitemos esa “generalidad”. pero en C# podemos definir el { this. A continuación creamos la clase ClienteOro que se deriva de Cliente. los delegados que hemos tratado. nas aplicaciones prácticas de esta posibilidad que ses del fuente 7 es para facilitar el uso de las mismas.MiFuncion.. seguramente la usaremos en casos muy con- Cliente y ClienteOro.inicio. multidifusión.Nombre = nombre. firma correcta. (ver el fuente 1).0). public ClienteOro() { } EventArgs e) public ClienteOro(string nombre) { . Aún no hemos terminado con algunas de las cosas interesantes o importantes de los delegados. Tanto en una como en otra cla. 47 . Ahora podemos usar cualquier función que reci.fundamentos datos que podemos usar como parámetros al llamar a pero siempre y cuando el método anónimo tenga la un delegado pueden ser del mismo tipo que está defi. mfd2 = co. pero a la hora ción de herencia entre el tipo usado y el definido en de usarlo podemos indicar cualquier objeto de un tipo el delegado. el segundo parámetro suele (o debería) ser una clase derivada de EventArgs. comprenderemos mejor cuando sepamos más sobre la estrecha relación de estas clases especiales con ClienteOro co = new ClienteOro(“Paco”).Nombre = nombre. un parámetro de tipo Cliente. va un saludo al nombre indicado en la propiedad Nombre Console. << dnm. los eventos. definiciones de estas clases. pero no adelantemos acontecimientos. ejemplo para poder bajarlo. } private void txtNombre_KeyPress( object sender. o de del método anónimo debe ser del mismo tipo que el cualquier tipo derivado. ya que cuan- NOTA do tratemos el tema de los eventos veremos algu- El hecho de definir un constructor con parámetro en las cla. plo podrá mostrar algo. } } La segunda forma. Definición simplificada de las clases cífica. } { this. } // método que intercepta ese evento de cualquiera de public virtual string MiFuncion(Cliente c) { estas dos formas: return “Que tal “ + c.Nombre. es decir. Esa forma de usar los delegados la ponda. MiFuncionDelegado mfd2. Como es costumbre en esta sección.. } class ClienteOro : Cliente { private void txtNombre_KeyPress( object sender. de la clase.Nombre.WriteLine(sco). de for. Si el compilador ve una rela. vamos a mfd3 = delegate(Cliente co2) {return “A sus pies “ + rediseñar la clase y el método MiFuncion para que devuel. debemos definirlos en ambas. ya que en Visual Basic siempre tendre- ma que en una sola instrucción podamos asignar el valor de mos que definir los parámetros de los eventos del la propiedad Nombre. metro el nombre a usar. indicado en la definición del delegado.