jueves, 9 de julio de 2015

Enlace Dinámico en C# - Parte 5: Tipos Estáticos en Expresiones Dinámicas, Funciones No Invocables, y Representación en Tiempo de Ejecución de Dinámicos

Índice

0. Introducción
1. Tipos Estáticos en Expresiones Dinámicas
2. Funciones No Invocables
2.1 Restricción en métodos de extensión
2.2 Restricción en una interfaz
2.3 Restricción de miembros base ocultos
3. Representación en Tiempo de Ejecución de Dinámicos
4. Conclusiones
5. Glosario
6. Literatura & Enlaces

0. Introducción

Esta quinta parte, y última, de la serie de Enlace Dinámico en C# comprenderá básicamente: el tratamiento de expresiones dinámicas compuestas por tipos estáticos y en particular cómo son resueltas en tiempo de ejecución. El siguiente tema que abordaremos, se enfoca en casos excepcionales donde el alcance de reconocimiento de tipos se pierde en tiempo de compilación: interfaces, miembros base ocultos, y métodos de extensión. Al finalizar, estudiáremos la representación en tiempo de ejecución de expresiones dinámicas.

1. Tipos Estáticos en Expresiones Dinámicas

Antes de entrar en detalle y considerar los aspectos más sobresalientes del papel que juegan los tipos estáticos durante el proceso de compilación y ejecución, creemos el siguiente ejemplo de código C# para tengamos una idea más práctica.


¿Cuál de los métodos será invocado cuando ejecutemos la expresión MostrarEnConsola(x, y);? Para empezar, notemos que esta expresión compromete un argumento, y:dynamic, luego, esta operación será resuelta en tiempo de ejecución para generar el enlace dinámico correspondiente. Además, teniendo en cuenta lo que hemos aprendido en las 4 partes anteriores de esta serie, podemos decir que la resolución de tipo para y será string, lo que en consecuencia hará que la versión sobrecargada de MostrarEnConsola sea invocada (líneas 23-26):

public static void MostrarEnConsola(object param1, string param2)
{
Console.WriteLine("C");
}

Compilación:


  1. csc /target:exe ResolucionEnlaceDinamico.cs

Ejecución assembly:


  1. .\ResolucionEnlaceDinamico.exe

> Prueba de ejecución: ideone.com.

> Prueba de ejecución (local):
Ejecución assembly ResolucionEnlaceDinamico.exe
Figura 1. Ejecución assembly ResolucionEnlaceDinamico.exe.

2. Funciones No Invocables

Entre las funciones que no pueden ser invocadas de manera dinámica, tenemos [1]:
  • Métodos de extensión, 
  • Miembros de una interfaz, y 
  • Miembros base ocultos por parte de una subclase.
La razón de estos tres escenarios restrictivos es que en la versión actual estable de C# (i.e., 5.0) no existe modo de resolver el tercer tipo adicional (aparte del objeto invocador, y el nombre de la función a invocar), además de ser requerido, en tiempo de compilación.

2.1 Restricción en métodos de extensión

En la invocación de métodos de extensión (recomiendo la lectura Métodos de Extensión en C#) se requiere que este tipo adicional sea resuelto implícitamente (mandatoriamente durante tiempo de compilación). Esta resolución corresponde con la clase estática que tiene definido el método de extensión en cuestión.

En [1] nos informan también:
"The compiler searches for it given the using directives in your source code..."
Además:
"...This makes extension methods compile-time-only concepts, since using directives melt away upon compilation..."

2.2 Restricción en una interfaz

En cuanto a interfaces, la especificación del tipo adicional se realiza mediante una conversión implícita o explícita (Interfaces en C# - Parte 1). Evidentemente, esta resolución se lleva a cabo en tiempo de compilación.

Supongamos que tenemos esta jerarquía de definición e implementación de interfaces:

interface IRadio
{
void Sintonizar();
}

public RadioDigital : IRadio
{
void IRadio.Sintonizar()
{
// implementación...
}
}

Ahora si lo que queremos es invocar el método Sintonizar, es necesario que efectúemos una conversión implicita:

IRadio radio = new RadioDigital(); // Conversión implícita a la interfaz
radio.Sintonizar();

Y respecto a la situación de resolución de tipos dinámicos:

IRadio radio = new RadioDigital();
dynamic dyn = f;
dyn.Sintonizar(); // Generación de excepción.

Técnicamente lo que sucede en este punto es la razón que nos dan en [1]:
~"...the compiler binds subsequent member calls to -IRadio- rather than -RadioDigital-, in other other words, to view that object through the lens of the IRadio interface. However, that lens is lost at runtime, so the DLR cannot complete the binding."

2.3 Restricción de miembros base ocultos

Tomemos como razón fuente la dada en [1]:
"...when calling a hidden base member, you must specify an additional type via either a cast or the base keyword; and that additional type is lost at runtime."
Para comprender a que se refieren con el uso de miembros base ocultos, podemos leer el artículo Ocultación de Miembros Heredados en C#. En este artículo hallaremos, además, los fundamentos que soportan el argumento dado en el extracto anterior. Y para ir un poco más, a fondo sugiero también la lectura del artículo Construcción Sintáctica base en C#.

3. Representación en Tiempo de Ejecución de Dinámicos

La expresión

typeof(dynamic) == typeof(object)

genera como valor de verdad true. Para estructuras tanto básicas (i.e., arreglos) o compuestas (i.e., listas), C# evalúa como verdadero las siguientes expresiones [1]:

typeof(List) == typeof(List<object>)

y

typeof(dynamic[]) == typeof(object[])

Esto ocurre porque [1]:
"Structurally, there is no difference between an object and a dynamic reference. A dynamic reference simply enables dynamic operations on the object it points to."
Luego esta operación este tipo de operaciones está permitida:

object obj = new StringBuilder();
dynamic dyn = obj;
dyn.Append ("OrtizOL - xCSw");

Console.WriteLine(obj); // Imprime: OrtizOL - xCSw


Esta conversión (línea 2), object a dynamic, lo que permite es ejecutar operaciones dinámicas en una instancia de object.


Podemos, también tomar la nota explícita dada en [1]:
Atributo System.Runtime.CompilerServices.DynamicAttribute
Figura 2. Atributo System.Runtime.CompilerServices.DynamicAttribute [1].

4. Conclusiones

Finalizamos este artículo y esta serie de Enlace Dinámico, explorando y comprendiendo las sutilezas de uso de tipos estáticos en expresiones dinámicas: a pesar que varios de estos tipos sean resueltos en tiempo de compilación, si un token de la expresión es dinámica, hay que dejar el trabajo a la DRL para que resuelva la invocación de la función en tiempo de ejecución. Por otro lado, también vimos algunas restricciones respecto a miembros de extensión, interfaces, y miembros base ocultos, que consisten en la realización de un elemento (tipo adicional) que es inherentemente identificado y resuelto en tiempo de compilación. Al final estudiamos la representación de dinámicos en tiempo de ejecución: el punto a resaltar es la composición referencial equivalente que existe entre object  y dynamic.


Lo siguiente que debemos estudiar para continuar nuestra ruta de aprendizaje de avanzados de C# es: Atributos.

5. Glosario

  • Arreglo
  • C#
  • Compilador
  • DLR
  • Estructura de datos
  • Interfaz
  • Resolución

6. 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]: Métodos de Extensión en C# - http://ortizol.blogspot.com/2014/09/metodos-de-extension-en-csharp.html
[3]: Interfaces en C# - Parte 1 - http://ortizol.blogspot.com/2014/05/interfaces-en-c-parte-1.html
[4]: Construcción Sintáctica base en C# - http://ortizol.blogspot.com/2014/02/construccion-sintactica-base-en-c.html
[5]: Ocultación de Miembros Heredados en C# - http://ortizol.blogspot.com/2014/01/ocultacion-de-miembros-heredados-en-c.html


J

No hay comentarios:

Publicar un comentario

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.