Índice
0. Introducción1. ¿Qué es el Enlace Dinámico?
2. Utilidad del Enlace Dinámico
3. Primer Ejemplo Básico de Enlace Dinámico
4. Enlace Estático y Enlace Estático
5. La Excepción RuntimeBinderException
6. Conclusiones
7. Glosario
8. Literatura & Enlaces
0. Introducción
Este artículo y como todos de la serie de C# Avanzando (capítulo 4), comprende temas que requieren mayor energía mental para su comprensión, pero su entendimiento se puede ver reflejado en construcciones software más robustas y sofisticadas, así que vale la pena ir más allá y entender este siguiente tema que resultará amplio: Enlace dinámico. En primer lugar, haremos una introducción que nos dará los fundamentos del enlace dinámico, su comparación con el enlace estático (el compilador resuelve todos los elementos programáticos en tiempo de compilación). Como es típico, introduciremos varios ejemplos para acercanos a su utilidad práctica. Al final exploraremos la excepción RuntimeBinderException.
Vale aclarar, como ya mencionamos, que debido a la complejidad de este tema, he decidido devidir su exploración y estudio en 5 partes integrales:
- Introducción al Enlace Dinámico, Enlace estático vs enlace dinámico, RuntimeBinderException.
- Enlace Personalizado, Enlace de Lenguaje
- La Palabra Clave dynamic, Conversiones, Diferencia entre var y dynamic
- Expresiones Dinámicas, Expresiones Dinámicas sin Receptores Dinámicos
- Tipos Estáticos en Expresiones Dinámicas, Funciones Non-Invocables
1. ¿Qué es el Enlace Dinámico?
En términos simples y directos, el enlace dinámico (dynamic binding), no es más que la resolución de tipos, miembros, y operaciones en tiempo de ejecución. A diferencia, el enlace estático (estatic binding), estas resoluciones se efectúan y se comprueban en tiempo de compilación.
2. Utilidad del Enlace Dinámico
Como se menciona en [1], el enlace dinámico es útil cuando en tiempo de compilación el programador conoce que ciertos elementos de programa (i.e., funciones, miembros, propiedades, operaciones) en existen, pero el compilador no.
Pero a fin de cuentas, ¿dónde reside la utilidad efectiva de este concepto? En las recetas C#:
- Receta No. 3-12 en C#: Crear un Objeto con Reflection
- Receta No. 3-14 en C#: Investigar los Atributos de un Elemento de Programa con Reflection
- Receta No. 3-15 en C#: Uso Programático para Investigar y Descubrir los Miembros de un Tipo
- Receta No. 3-16 en C#: Invocar un Miembro de un Tipo con Reflection
se estudia y se practica el concepto de .NET Reflection (el cual, para recordar, es una técnica que nos permite extraer la meta-información que está asociada un tipo, un assembly, etc., en tiempo de ejecución), y es aquí donde el enlace dinámico juega un papel importante; además, de permitir la interoperabilidad con lenguajes dinámicos como IronPython [6] (implementación en .NET del lenguaje de programación Python [7]).
(Aún todo estas definiciones y respuestas pueden sonar un poco abstractas, pero a medida que avancemos con paciencia se nos aclararán muchas dudas y preguntas respecto a este importante tema que un programador debe conocer, siempre y cuando tenga la disposición de avanzar en su oficio y conocer prácticas avanzadas y sofisticadas de este increíble lenguaje que es C# y la plataforma .NET.)
3. Primer Ejemplo Básico de Enlace Dinámico
Asumamos que con el método ObtenerObjeto obtenemos un objeto de algún tipo, luego con la declaración de una variable a la que llamaremos variableDinamica le asignamos el valor de retorno del método anterior, y finalmente invocamos sobre esta variable un método que como programadores sabemos que existe: RealizarTransferencia. En código C# tenemos entonces:
dynamic variableDinamica = ObtenerObjeto();
variableDinamica.RealizarTransferencia();
(Es importante que la variable esté marcada con la palabra clave contextual dynamic, de lo contrario no nos beneficiáremos de la resolución de enlace dinámico en tiempo de ejecución.)
Con el hecho de haber especificado dynamic para la variable variableDinamica, le especificamos al compilador hacer caso omiso al establecimiento de enlaces con tipos, operaciones, funciones, propiedades, etc en tiempo de compilación. Todo las resoluciones de miembros se realizará efectivamente en tiempo de ejecución. (He aquí una primera ventaja de esta técnica.)
4. Enlace Estático vs. Enlace Dinámico
El enlace estático lo asociamos con la resolución de tipos, métodos, propiedades, y demás elementos de programa en tiempo compilación (como ya se ha repetido una y otra vez). Por ejemplo, si hacemos uso del siguiente código en un archivo de código fuente C#:
Avion avion = new AvionComercial();
avion.Despegar();
Console.WriteLine("Capacidad pasajeros: {0}", avion.Capacidad);
el compilador a la hora de, valga el pleonasmo, compilar este código conoce en etapa temprana (early stage) las resoluciones de tipos (Avion), métodos (Despegar), y propiedades (Capacidad), las cuales deben existir para que el proceso de compilación sea satisfactorio según esta especificación de código. En caso contrario, asumiendo en este caso que la propiedad Capacidad no existiera, se generaría el error CS1061 [9] enunciando el mensaje:
Type `Avion' does not contain a definition for `Capacidad' and no extension method `Capacidad' of type `Avion' could be found. Are you missing an assembly reference?
Vale añadir que la asociación o enlace, por ejemplo en el caso del método Despegar, se hace de forma descendente en la jerarquía de herencia:
- El compilador busca la definición de Despegar en la subclase AvionComercial.
- De no haberse encontrado en la definición de la subclase anterior, el compilador buscará en cualquier superclase de la jerarquía de herencia.
El compilador también buscará por métodos de extensión (Métodos de Extensión en C#) y métodos con parámetros opcionales.
Por otra parte, si declaramos una variable de object llamada avion y le asignamos una referencia a un subtipo, e.g., AvionMilitar, e intentamos especificar algo como:
avion.Despegar();
el compilador generará un error de compilación (CS1061 [9]) advirtiendo que object no contiene una definición de Despegar y cualquier otro método de extensión con esta firma.
Podemos intuir hasta este punto, que el enlace estático presenta una limitación de alcance en la resolución de tipos, propiedades, métodos, etc. Evidentemente, en este tipo de escenarios es donde el enlace dinámico juega un papel crítico para la construcción de soluciones más avanzadas y sofisticadas, es decir, que sea en tiempo de ejecución que efectúen las resoluciones de tipos, métodos, propiedades y otros elementos de programa.
Para ilustrarlo, si escribimos:
dynamic avion = new AvionComercial();
avion.Despegar();
el compilador no generará ningún error o advertencia, debido a que la resolución se efectúa en tiempo de ejecución dependiendo de la definición existente en este mismo ámbito de tiempo, y no del tipo en tiempo de compilación [1].
5. La Excepción RuntimeBinderException
También nos podemos cuestionar qué ocurre cuando ni tanto el enlace estático ni el enlace dinámico son capaces de resolver el elemento de programa (e.g., tipo, método, propiedad). En esta circunstancia el administrador de excepciones de la CLR lanza la excepción RuntimeBinderException [10] (namespace Microsoft.CSharp.RuntimeBinder).
Como instancia de ejemplo, veamos:
dynamic avion = new AvionComercial();
avion.Aterizar();
En el mundo real no desearíamos que un avión comercial no tuviera la capacidad de aterrizar, pero bueno, para ir al quid del asunto, asumamos que el enlace dinámico no fue capaz de resolver el método Aterrizar, en este escenario se lanza la excepción RuntimeBinderException con el mensaje:
'Avion' does not contain a definition for 'Aterrizar'.
6. Conclusiones
En esta primera parte de Enlace Dinámico sólo hemos rasgado los fundamentales de esta técnica de resolución de elementos de programa. Exploramos su definición y su uso básico. Recurrimos, también, a la comparación con la resolución de enlace estático para evaluar la ventaja programática de resolver tipos en tiempo de ejecución. Trazamos los básicos de la excepción RuntimeBinderException para entender cómo podemos controlar los problemas que se pudieran generar cuando ya no es posible resolver el elemento de programa en tiempo de éjecución. En la segunda entrega de esta serie veremos en qué consiste el enlace personalizado y el enlace de lenguaje.
7. Glosario
- .NET Reflection
- CLR
- Compilador
- dynamic
- Elemento de programa
- Enlace dinámico
- Enlace estático
- Jerarquía de herencia
- Propiedad
- Resolución
- Subclase
- Superclase
- Tiempo de compilación
- Tiempo de ejecución
8. Literatura & Enlaces
[1]: C# 5.0 in a Nutshell by Joseph Albahari and Ben Albahari. Copyright 2012 Joseph Albahari and Ben Albahari, 978-1-449-32010-2.[2]: Receta No. 3-12 en C#: Crear un Objeto con Reflection - http://ortizol.blogspot.com/2014/06/receta-no-3-12-en-c-crear-un-objeto-con-reflection.html
[3]: Receta No. 3-14 en C#: Investigar los Atributos de un Elemento de Programa con Reflection - http://ortizol.blogspot.com/2014/06/receta-no-3-14-en-csharp-investigar-los-atributos-de-un-elemento-de-program-con-reflection.html
[4]: Receta No. 3-15 en C#: Uso Programático para Investigar y Descubrir los Miembros de un Tipo - http://ortizol.blogspot.com/2014/06/receta-no-3-15-en-csharp-uso-programatico-para-investigar-y-descubrir-los-miembros-de-un-tipo.html
[5]: Receta No. 3-16 en C#: Invocar un Miembro de un Tipo con Reflection - http://ortizol.blogspot.com/2014/06/receta-no-3-16-en-csharp-invocar-un-miembro-de-un-tipo-con-reflection.html
[6]: Iron Python - https://en.wikipedia.org/wiki/IronPython
[7]: Python - https://en.wikipedia.org/wiki/Python_(programming_language)
[8]: Métodos de Extensión - http://ortizol.blogspot.com/2014/09/metodos-de-extension-en-csharp.html
[9]: Compiler Error CS1061 - https://msdn.microsoft.com/en-us/library/bb383961.aspx
[10]: RuntimeBinderException Class (Microsoft.CSharp.RuntimeBinder) - https://msdn.microsoft.com/en-us/library/microsoft.csharp.runtimebinder.runtimebinderexception(v=vs.110).aspx
J
hola, me gustaria saber como obtener las propiedades de un objeto con reflection que
ResponderEliminartiene otro objeto como atributo o una lista de objetos de otra clase como atributo,
por ejemplo: clase persona tiene como atributo a la clase domicilio o podria ser una
lista del tipo domicilio como atributo. Esto es posible mediante reflection???
te agradeceria tu respuesta ya que llevo tiempo intentando resolver
esta situacion y nada...
Hola Melisa. Espero que estés bien.
ResponderEliminarClaro que lo puedes hacer.
Apóyate en las recetas Capítulo 3 -Receta No. 3-x en C#- publicadas en este blog.
Esta es una de ellas: https://ortizol.blogspot.com.co/2014/06/receta-no-3-14-en-csharp-investigar-los-atributos-de-un-elemento-de-program-con-reflection.html
[Nota: Algunas secciones de código no se despliegan correctamente debido a que están en un pastebin no compatible, sin embargo se muestran los enlaces alternativos para visualización del código.]
Saludos desde Bogotá.