Los siguientes posts sobre Delegados que arrancamos con esta
primera parte, pretenden ser algo más que una simple pasada sobre lo que nos
ofrece esta clase del CLR y su uso en LinQ. Estos posts intentan profundizar
dentro de su usabilidad en el Framework ya que considero que es una de las partes
más difícil de comprender y de dominar, y su comprensión total, nos hace no tener ningún
tipo de barrera en LinQ dentro de su parte más avanzada.
La definición más lógica que suele realizarse cuando
hablamos de un delegado, es que es
lo más parecido a un puntero a
una función en C++.
Esto no es del todo cierto, ya que un delegado es una clase y no un tipo.
Un delegado
es una clase del CLR, que tiene la
capacidad de almacenar una o n
instancias de un método(s), eso sí, los métodos a almacenar, tienen que
cumplir una firma específica
indicada en la firma del delegado.
Tenemos la siguiente definición de delegado:
Este delegado
solo admite referencias a métodos que devuelvan un string y reciba un único parámetro de tipo string.
Este podría ser un método compatible para él.
Y podríamos realizar la asignación
del mismo de la siguiente manera:
De esta forma ya tendríamos almacenada la referencia a este método y podríamos hacer con él lo
que nos diera la gana: pasarlo por parámetros, ejecutarlo, etc.
Vale la pena destacar que en la asignación estamos añadiendo
el nombre del método sin ‘()’
ni parámetros, y esto significa que lo que le estamos facilitando es la dirección de memoria del método, el AddressOf en Visual Basic.
Como podemos ver en su instanciación no vemos por ninguna
parte el uso de la palabra reservada new,
esto es así, porque el tipo Delegate,
es un tipo inmutable, y esto
significa que cada vez que modificamos algo de la referencia(s) a la(s) que
apunta el objeto se reinstancia
de nuevo.
Esta llamada sería completamente equivalente:
Esta llamada sería completamente equivalente:
Esto nos puede recordar mucho al uso de la clase string y a las estructuras, ya que estas también son inmutables.
Para ejecutar el método almacenado en nuestro delegado, haremos lo siguiente:
Esta es una forma contraída de ejecución, la manera larga
sería así:
Propiedades y métodos más
interesantes
Daremos una breve descripción de las propiedades y métodos
más interesantes de la clase Delegate,
con el fin de entender un poco mejor las entrañas de esta clase. Los iremos
viendo con profundidad más adelante.
Propiedades
Solo tiene dos y son:
- Method .- Propiedad de solo lectura que obtiene la descripción del método que contiene. En caso de guardar referencia a más de un método, este nos dará la información del último añadido. Es de tipo System.Reflection.MethodInfo.
- Target .- Propiedad de tipo object de solo lectura que nos informa del propietario del método, para ser más exactos de la referencia propietaria. Al igual que con la propiedad Method, en caso de guardar más de un método y ser cada uno de referencias diferentes, este informará solo de la última añadida. Si los métodos referenciados son estáticos (static) está variable tomará el valor null.
Métodos de instancia:
- Clone .- La clase Delegate implementa la interfaz ICloneable, por lo que tiene la capacidad de poder clonarse.
- GetInvocationList .- Devuelve el conjunto de objetos de tipo Delegate correspondientes a los métodos que apunta.
- Invoke .- Llama a la ejecución del método(s) al/los que apunta.
- BeginInvoke y EndInvoke .- Realiza llamadas asíncronas de los métodos.
Métodos Estáticos:
- Remove .- Elimina la última referencia a método añadida.
- RemoveAll .- Elimina todas las referencias que contiene el objeto facilitado por parámetros.
- Conbine .- Combina/añade referencias de uno o varios delegados.
Como veremos con Multicast
Delegate, estos métodos casi no tienen uso, ya que se han facilitado
su uso con sobrecargas de operadores.
Aumentando el dinamismo y la
versatilidad de nuestros métodos
Los delegados nos permiten una versatilidad muy grande,
dando a nuestros métodos y a nuestras clases una dimensión mucho más extensa,
ampliando la capacidad de sus argumentos con acciones y no solo con valores o
referencias.
Vamos a ver un ejemplo, que intenta demostrar la parte
práctica de los delegados. Debemos verlo como método didáctico, ya que según vayamos avanzando, nos daremos cuenta que
con la inclusión de métodos
anónimos, expresiones
lambda y operadores
de consulta, el dinamismo aumenta de manera estratosférica.
El ejemplo consta de una clase inicial llamada AccionesConEnteros, que intenta
emular una clase con acciones cotidianas de enteros, pero llevadas a la
finalidad de transformar una colección de enteros en una colección de strings directamente salida del
horno para ser impresa. Como veremos esta colección de enteros puede sufrir una
serie de variaciones en su salida según nuestro gusto.
Lo primero importante a resaltar en la clase (mejor dicho en
sus namespace) es la
definición de dos delegados:
La firma de estos dos delegados es la coincidente para una
serie de métodos de la clase y lo que es más importante servirán de tipo de
parámetro para el método principal.
Ahora vamos a ver el método principal de la clase:
El método principal TransformarListaValoresParaImpresion,
toma 4 parámetros:
- listaValores .- De tipo List<int>, representa la lista de valores enteros que serán comprobados y trasformados en strings para su impresión.
- comparación .- De tipo DelegadoComparacion, representa el método que realizará la comparación de los valores enteros.
- acción .- De tipo DelegadoAccion representa la acción de sustitución que se realizará al transformar el tipo int en string.
- mensajeAccion .- De tipo string, muestra el mensaje que se podrá acoplar en el proceso de transformación de int a string.
Continuando con la clase, vemos que posee 2 grupos de métodos, que atesoran 2
métodos cada uno y que concuerdan con cada una de las firmas de los delegados
iniciales, éstos podrán ser utilizados para realizar la comparación o para
realizar la acción de transformación:
Importante resaltar que aquí se podrían añadir todos los
métodos que creyéramos necesarios y sin limitaciones, la única restricciones
que tendrían que cumplir con la firma
de sus delegados, para luego ser usados como parámetros en el método principal TransformarListaValoresParaImpresion.
Añado el código completo de la clase:
Ahora añadiremos un ejemplo de uso:
Con el siguiente resultado:
Como podemos ver en los comentarios, estamos haciendo uso de los métodos de comparación y acción que nos brinda la clase AccionesConEnteros, pero podríamos crearnos los nuestros propios (cumpliendo la firma claro) dentro de la clase donde se realiza la ejecución y serían completamente válidos.
Lo hemos hecho:
Hemos añadido dos métodos nuevos y los hemos sustituido en
la llamada al método de trasformación, con el siguiente resultado:
Y hasta aquí la primera parte sobre delegados, en el siguiente post entraremos más en materia sobre los delegados genéricos.
No hay comentarios :
Publicar un comentario