> Manuales > Ayudas técnicas

En este artículo vamos a tratar la que tal vez sea la más controvertida y revolucionaria de las novedades: el tipado dinámico (dynamic typing).

Traición, dicen los más ortodoxos. Después de que .NET ha alabado tanto la seguridad otorgada por el tipado estático (static typing), que entre otros beneficios permite dar soporte a una maravilla como Intellisense, resulta que ahora nos salen con eso de los tipos dinámicos, para posponer el control de tipos a tiempo de ejecución… ¿Y los riesgos que eso me va a introducir? Oportunismo, dicen los detractores. ¿Me vienen a descubrir eso ahora? Si ya lo teníamos con Python y con Java - Script, lenguajes que no nos imponen la “camisa de fuerza” del tipado estático…

Como en todo, los extremismos son malos. Lo que sí puede decirse que no es estático es la voluntad de Microsoft de evolucionar, siempre con la visión de potenciar y hacer más grata la labor de los desarrolladores. En este mundo “dinámico” coincidimos con los objetivos de .NET 4.0 de unificar paradigmas, ampliando el arsenal de recursos para abordar los diferentes escenarios que cada vez más se nos presentan.

Es cierto que hasta ahora en raras ocasiones nos hemos encontrado con problemas que no hayamos podido resolver con el tipado estático; en todo caso, aderezando nuestros programas con un poco de reflexión (reflection). Pero ya tenemos Silverlight, y con éste la posibilidad de ejecutar código .NET en el cliente Web; y ya que ahora tenemos esa gran posibilidad, entonces debemos facilitar la programación de ese código .NET, de modo que las aplicaciones Web puedan lidiar en tiempo de ejecución con tipos desconocidos, que no se puedan prever estáticamente. De este modo, ese código .NET podría entenderse con lo que ya está por ahí hecho en la Web usando JavaScript u otros lenguajes de script que son inherentemente dinámicos.

Que sea estático lo que pueda ser estático

Los ordenadores de hoy tienen esencialmente la misma arquitectura que la de sus bisabuelos: procesador más memoria. En la memoria lo mismo se ponen datos que instrucciones; todo depende de cómo se le pide al hardware que interprete el contenido de esa memoria. Pero el hardware no aporta mucha protección: si mandamos a interpretar como instrucción lo que realmente fue guardado como dato, en el mejor de los casos se producirá un error detectable si la representación de dicho dato no se corresponde con el formato de una instrucción. Por otro lado, si una operación de hardware interpreta como dato lo que tenga la memoria, el hardware verifica que el “dato” esté en el formato adecuado, por ejemplo una representación en punto flotante que corresponda a la aritmética, o una dirección de memoria que sea accesible, y poco más. Si el desarrollo de software ha llegado hasta aquí, ha sido gracias a las capas de abstracción que han ido poniendo los lenguajes de programación, los compiladores y los marcos de trabajo (frameworks) que se han ido sedimentando con el pasar de los años, de lo que .NET es un gran exponente.

Tipado estático es poder describir en el código fuente que escribimos los tipos que creamos y los tipos de nuestras entidades (variables, propiedades, parámetros, tipos de retorno de las funciones, etc.) para que este texto sea sometido a compilación. Como todo se sabe, o se puede deducir a partir del texto de los programas o de la información de otros componentes ya compilados, el compilador podrá detectar entonces cualquier incongruencia en el uso inadecuado de los tipos y de las entidades que se definen a partir de ellos. De este modo, el código generado por la compilación podrá ejecutarse con la seguridad de que no se producirá un error imprevisto causado por inconsistencia en el uso de las operaciones o por intentar aplicar una operación inexistente.

El paradigma de la Programación Orientada a Objetos (POO) es un buen ejemplo que propicia este tipado estático. Si a partir del código fuente se puede saber que x es una entidad de tipo A, si un método M es aplicable al tipo A, si el método M tiene un parámetro de tipo B y si b es una entidad de tipo B, entonces el compilador puede comprobar que una llamada x.M(b) es correcta y generar un código que se ejecute con tranquilidad, sin tener que estar haciendo comprobaciones en tiempo de ejecución. Por otro lado, una herramienta como Intellisense podrá desplegar las opciones de A (que incluyen el nombre M) apenas tecleemos x..

.NET ha evolucionado haciendo cada vez más flexible la forma de usar estáticamente los tipos, porque en los lenguajes de programación, a diferencia que en la filosofía, el concepto de estático no implica carencia de evolución1. Las jerarquías de tipos y el enlace tardío (late binding), logrado en C# a través de las interfaces y la redefinición (override) de métodos virtuales, nos aportan flexibilidad sin perder seguri.NET ha evolucionado haciendo cada vez más flexible la forma de usar estáticamente los tipos, porque en los lenguajes de programación, a diferencia que en la filosofía, el concepto de estático no implica carencia de evolución1. Las jerarquías de tipos y el enlace tardío (late binding), logrado en C# a través de las interfaces y la redefinición (override) de métodos virtuales, nos aportan flexibilidad sin perder seguridad. La genericidad nos permite definir estáticamente patrones a partir de los cuales podemos definir nuevos tipos. En C# 4.0 se continúa perfeccionando el tipado estático con la varianza y la covarianza, aportando aún más flexibilidad.

Inferencia de tipos

Históricamente, para garantizar el tipado estático, facilitarse el trabajo, o hacer más legible la lectura humana del código, muchos lenguajes y compiladores han obligado a declarar explícitamente las entidades. Sin embargo, esto no es un requerimiento para que haya chequeo estático de tipos (static type checking). Por ejemplo, en C# 3.0 podemos escribir no solo int i = 2; sino también var i = 2;. En el segundo caso, el compilador infiere que el tipo de i es int porque la parte derecha de la asignación es de tipo int. Si esta fuera la única diferencia, usted podría preguntarse ¿dónde está la gracia de var? Pero si analiza la siguiente sentencia LINQ:

var films = from f in cineDB.Films
where f.Rating == 5
orderby f.Title
select new {
Title = f.Title,
Genre = f.Genre.Name,
Director = f.Director.Name
};

Comprenderá que sería un fastidio tener que definir un tipo que exprese la estructura de las tuplas resultantes, para tener luego que declarar explícitamente la variable films como de dicho tipo. En definitiva, manipular tal tipo por su nombre no es lo que interesa en esta situación, sino saber que los valores resultantes de la consulta disponen de las propiedades Title, Genre y Director (y que, claro, Intellisense nos las muestre). De este modo, se puede escribir con confianza estática:

foreach (var f in films)
Console.WriteLine("{0,-24} {1,15} ({2})",
f.Title,
f.Genre.Name,
f.Director.Name);

En el ejemplo anterior de LINQ no es que no haya tipado estático, sino que el compilador infiere el tipo formado en la cláusula select y asignado a la variable films. La inferencia de tipos es una característica de muchos lenguajes funcionales que erróneamente lleva a algunos a decir que éstos no tienen tipado estático. De hecho, F# (que con su inclusión en Visual Studio 2010 ya ha sido reconocido como hijo legítimo de la familia .NET) es un lenguaje funcional que tiene inferencia de tipos (aunque no prescinde totalmente de la declaración estática, cuando es conveniente hacer más legibles o viables algunas situaciones).

Si inferir los tipos es mejor que indicarlos explícitamente o viceversa es, a fin de cuentas, un problema de gusto sintáctico. Pero lo que no debe dejar dudas es que en ambos casos hay tipado estático; el tipo está ahí, más o menos evidente, pero ahí en el texto, es conocido en tiempo de compilación, y por tanto nada imprevisible ocurrirá durante la ejecución.

Recordamos a un físico que defendía a FORTRAN vs. Pascal, no porque su aritmética fuese más eficiente sino “porque no le obligaba a declarar las variables”. El compilador de FORTRAN lo que hacía era inferir el tipo de las variables según la letra con la que empezara su nombre. Hay programadores que defienden a Python sólo porque se quitan de encima lo que para ellos es “la camisa de fuerza del tipado estático”.

Pero libertad no es libertinaje. Abogamos porque todo lo que pueda definirse estáticamente se defina estáticamente, aprovechando todas las flexibilidades y recursos que nos ha ido ofreciendo .NET y su familia de lenguajes.

Los llamados lenguajes dinámicos son aquellos que ofrecen recursos que permiten operaciones estáticamente no verificables sobre datos para los cuales no se tiene un tipo estáticamente conocido en el contexto en que se aplican dichas operaciones. .NET 4.0 y C# 4.0 han incluido la posibilidad de tener tipado dinámico.

El tipo dynamic

El código a continuación es un ejemplo de lo que ahora podemos tener en C# 4.0 sin que el compilador proteste:

dynamic d = DevolverObjetoDeTipoDesconocido();
d.M();

La variable local d ha sido declarada “estáticamente” como de tipo dynamic, que es un tipo integrado soportado por el compilador, y que se puede usar en la mayoría de los lugares en que puede usarse un tipo. Este código compila sin conocerse quién es M y si realmente existirá en tiempo de ejecución. Será en ejecución, si el objeto que se asoció a d es de un tipo al que no se le puede aplicar un método M, que se produciría una excepción.
Note que lo que se hace en el ejemplo anterior no es lo mismo que hacer:

object x = DevolverObjetoDeTipoObject();
((C)x).M();

Porque en este último caso tenemos que saber estáticamente, al escribir el código, que existe un tipo C y que ese tipo C tiene un método M. En este caso, la operación de casting (C)x lo que hace es generar un código IL que asegura en tiempo de ejecución que el tipo del objeto al que hace referencia x conforma con C.

En el caso de dynamic, el compilador, en lugar de emitir código IL para llamar a un método M (lo que no puede hacer porque no sabe siquiera si el tipo al que hará referencia d tendrá un método M), lo que hace es emitir una llamada dinámica, de la que se hará cargo un nuevo motor de ejecución montado sobre el CLR denominado DLR (Dynamic Language Runtime) para determinar la existencia de M y ejecutar la acción correspondiente.

Podemos pensar que esto ya lo podíamos lograr usando reflexión, haciendo algo como:

object x = DevolverObjetoDeTipoDesconocido();
Type t = x.GetType();
MethodInfo M_Method = t.GetMethod("M");
M_Method.Invoke(x, new object[] { });

Pero la ventaja de usar dynamic es no solo la brevedad y comodidad que nos brinda la nueva notación con respecto al código anterior, sino también que la maquinaria del DLR lo ejecutará de manera más eficiente4. El DLR nos ofrece además la posibilidad de “personalizar” esta invocación dinámica, lo que veremos más adelante.

Como para C# dynamic es un especificador de tipo, se puede usar para declarar todo tipo de entidades. Por ejemplo:

class D
{
public dynamic MiCampo;
public dynamic MiPropiedad { get; set; }
public dynamic MiMétodo(dynamic d)
{
return d.M();
}
public delegate dynamic MiDelegado(dynamic d);
}

¿Cuál es la utilidad del tipado dinámico?

Pero, ¿por qué esto de tipado dinámico en .NET? ¿Qué es lo que hace falta hacer dinámicamente?
Algunos llaman “programación dinámica” 5 al paradigma bajo el cual se programa con el precepto de que no se puede hacer una comprobación estática (es decir, en tiempo de compilación, sin depender de eventos o datos de ejecución) de cuáles son las operaciones que pueden aplicarse sobre las entidades.

Programar bajo esta pauta puede parecer contradictorio a los programadores acostumbrados al chequeo estático de tipos. Ya no tendríamos la ayuda de Intellisense, y habrá que estar conscientes de que se puede errar en la aplicación de un método u operación sin que el compilador nos avise de nada, y el error entonces se manifestará como excepción en tiempo de ejecución. Esta propuesta de usar la especificación dynamic nos obliga a indicarle explícitamente al compilador que estamos conscientes de que eso es lo que queremos al usar las entidades que así se definan, y que asumimos la responsabilidad de lo que pueda pasar.

Varios son los escenarios en los que el tipado dinámico puede resultar la elección más acertada: lidiar con un diseño incompleto o deficiente cuando no nos podemos dar el lujo de reestructurar el mismo; prototipado rápido; interoperar con otros entornos; o trabajar con tipos desconocidos que aparecen durante la ejecución de una aplicación que no puede detenerse para realizar un nuevo ciclo de reescritura de código y compilación (lo cual en el contexto Web no es nada raro).

Poner “parches” a problemas de diseño

En nuestro ya lejano primer trabajo para dotNetManía, en el que hablamos de la reflexión en .NET, describimos un escenario en el que usando Windows Forms convenía aplicar un método tanto sobre un ComboBox como sobre un ListBox. Tal método necesitaba acceder a propiedades comunes a estos dos tipos, pero que no estaban factorizadas en un supertipo común a ambos formando una jerarquía.

Una posible solución es la que se muestra en el listado 1. El lector podrá apreciar los inconvenientes del código similar que hay que repetir y de la rigidez para adaptar dicho código cuando se quiera lidiar con un nuevo tipo que también disponga de dichos métodos comunes.

Listado 1
void Configure (object control)
{
if (control is ComboBox)
{
ComboBox combo = (ComboBox)control;
combo.BeginUpdate();
combo.SelectedIndexChanged += newEventHandler(ciertoMetodo);
combo.Items.Add("Default");
combo.Items.Add("Auto");
combo.Text = "Default";
combo.Sorted = true;
combo.EndUpdate();
}
else if (control isListBox)
{
ListBox list = (ListBox)control;
list.BeginUpdate();
list.SelectedIndexChanged += newEventHandler(ciertoMetodo);
list.Items.Add("Default");
list.Items.Add("Auto");
list.Text = "Default";
list.Sorted = true;
list.EndUpdate();
}
}

Propusimos un mecanismo basado en reflexión que permitía asignar dinámicamente un objeto de alguno de estos tipos a una variable del tipo de interfaz IListControl, en el que habíamos reunido la factorización común a ambos tipos y que sin embargo no había sido concebida en la jerarquía original.

Usando directamente la reflexión se puede mejorar el efecto del listado 1, mediante un código como el que se muestra en el listado 2. Aquí se tiene ahora la ventaja de que no tenemos que conocer estáticamente los nombres de los tipos ComboBox y ListBox, sino solamente la existencia de los métodos que queremos usar. Además, este código funcionará también sobre objetos de cualquier otro tipo que disponga de dichos miembros, sin que tengamos que modificar el mismo.

Listado 2
void Configure (object control)
{
Type controlType = control.GetType();
MethodInfo met = controlType.GetMethod("BeginUpdate");
met.Invoke(control, newobject[] { });
EventInfo ef = controlType.GetEvent("SelectedIndexChanged");
ef.AddEventHandler(this, newEventHandler(ciertoMetodo));
PropertyInfo prop = controlType.GetProperty("Items");
IList col = (IList)prop.GetValue(control, null);
col.Add("Default");
col.Add("Auto");
prop = controlType.GetProperty("Text");
prop.SetValue(control, "Default", null);
prop = controlType.GetProperty("Sorted");
prop.SetValue(control, true, null);
met = controlType.GetMethod("EndUpdate");
met.Invoke(control, newobject[] { });
}

Pero, evidentemente, el código del listado 2 es una “guarrada”. Ahora con dynamic esto se podrá expresar de un modo mucho más breve y natural, como se muestra en el listado 3.

Listado 3
void Configure (dynamic control)
{
control.BeginUpdate();
control.SelectedIndexChanged +=
newEventHandler(ciertoMetodo);
control.Items.Add("Default");
control.Items.Add("Auto");
control.Text = "Default";
control.Sorted = true;
control.EndUpdate();
}

Acceder a datos de modelos estáticamente desconocidos o dinámicamente muy variables

LINQ es sin lugar a dudas una bendición, no solo por su genial integración de recursos avanzados de programación, sino por permitirnos reducir considerablemente la impedancia entre el mundo en el que representamos nuestros datos (mayoritariamente relacional) y el mundo en el que se programa la lógica de negocio (mayoritariamente orientado a objetos). Pero, ambiciosos al fin, queremos aspirar a más: ¿y si quiero que mi aplicación pueda operar sobre cualquier base de datos siguiendo unas pocas convenciones? ¿Si el modelo de datos sobre el que trabajamos cambia mucho dinámicamente? ¿Hay que reprogramar la capa de acceso a los datos, reescribir las consultas y recompilar cada vez?

Desde los principios de ADO.NET, y más ahora con LINQ to SQL y Entity Framework (EF), para acceder a los datos de las tablas relacionales se ha tomado como práctica el generar un ORM asociado a la BD. Esto es, generar un código que contenga por cada tabla la definición de un tipo donde se mapean las columnas con propiedades y las filas (tuplas) con los objetos que de dichos tipos se pueden crear. En la mayoría de los escenarios esto ha resultado ser lo más cómodo y elegante.

¿Pero qué pasa si lo que se quiere es manejar datos de una base de datos desconocida estáticamente? Las herramientas ORM se emplean mayoritariamente en entornos estáticos en los cuales incluimos el código generado como parte de nuestro proyecto, a compilarse como parte del ensamblado correspondiente. Algunos ORM, como el de EF, permiten generar y compilar tal código en tiempo de ejecución, lo cual aparentemente resuelve el problema del desconocimiento estático, pero ¿hasta qué punto y a qué precio?

LINQ es un recurso estático, donde el tipo de las entidades que se definen han de ser estáticamente verificables; por lo tanto, no se puede escribir con LINQ la forma de consultar una tal “base de datos dinámica”, pues tales tipos, generados dinámicamente por EF, no estarán disponibles en el entorno estático en el que se escribió el código LINQ de la consulta, lo cual se hizo en un momento en el que tales tipos aún no existían o se desconocían.

Considere un escenario en el que se quiere hacer consultas a distintas bases de datos GIS7. Por lo general, en las bases de datos del mundo GIS las tablas con contenido espacial suelen tener por convenio columnas llamadas xmin, xmax, ymin, ymax. Sería deseable entonces que, aún cuando no se conociera estáticamente la base de datos, se pudiera hacer algo como:

string miTabla = f(); // el nombre de la tabla no se conoce hasta la ejecución
var q = from c in objectContext.CreateQuery(miTabla)
where c.xmin > 100 && c.ymin > 100 &&
c.xmax < 900 && c.ymax < 900
select c;

Pero si la fuente objectContext fuese un contexto de datos de EF obtenido por generación y compilación en tiempo de ejecución, éste sería un caso en que el compilador no podrá verificar el uso de las propiedades que se aplican a c, aún cuando el programador tenga la certeza de que el nombre asignado a miTabla sí se corresponde a una tabla de la BD con unas tales columnas xmin, xmax, ymin y ymax, y que por tanto el ORM que EF generaría en ejecución si mapeará dicha tabla con un tipo que tendrá propiedades con estos nombres.

Otro escenario interesante puede ser el de una aplicación que tenga que acceder a muchas bases de datos diferentes pero para ejecutar operaciones rápidas, pocas o muy específicas. Generar un ORM completo y su correspondiente ensamblado para cada una de las bases de datos implicaría una sobrecarga de procesamiento y memoria.

Entonces, si en tales escenarios la tabla es estáticamente desconocida, tratémosla como dynamic… Le aplicamos las propiedades que sabemos que son “mapeables” a sus columnas ¿y ya? Pero esto no es tan simple como se dice. ¿Si no hay un ORM, quién se ocupa de resolver tal mapeo?

Tengamos en cuenta que no queremos renunciar a la sintaxis objeto.Propiedad para acceder a los datos de una tabla. Podríamos pensar entonces que los objetos que se obtengan de la tabla sean de tipo dynamic, a los cuales les aplicaríamos una propiedad dinámicamente y que luego sean los objetos los que “resuelvan” en ejecución la correspondencia de las propiedades con las columnas reales de dicha tabla.

Para poder “personalizar” esta resolución, que determina cuál propiedad aplicar, se puede usar el tipo System.Dynamic.DynamicObject. Heredando de este tipo y redefiniendo algunos de sus métodos podemos crear objetos dinámicos que se encargan de interactuar con el DLR y que saben cómo “resolver” los intentos de aplicarle las propiedades (en este ejemplo, determinar a cuáles columnas de una tabla se está accediendo). El listado 4 nos ilustra cómo usar de forma dinámica objetos de tipo DataRow obtenidos de ADO .NET.

Listado 4
public class DynamicRow : DynamicObject
{
DataRow row;
public DynamicRow(DataRow row)
{
this.row = row;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = row[binder.Name];
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
row[binder.Name] = value;
return true;
}
}

Observe que DynamicRow no es un objeto que exactamente tenga una propiedad definida por cada columna, sino que las redefiniciones que hace de los métodos TryGetMember y TrySetMember son las que se aplican cada vez que se intente acceder a una propiedad en una variable declarada como dynamic. Considere, por ejemplo, la siguiente variable declarada de tipo dinámico:

dynamic x = new DynamicRow(myDataRow);

Si luego se intentara acceder a una tal propiedad Title:

string title = x.Title;

El codigo generado por el compilador de C# 4.0 utilizara el DLR e invocara a nuestra version del metodo Try] GetMember. Observe que una implementacion como la del listado 4 es la que resuelve realmente como acceder al dato (en este caso, un elemento del DataRow). En el codigo del listado 5 se utiliza este tipo DynamicRow para consultar el titulo, ano y calificacion de una tabla de peliculas.

Listado 5
private void PrintData(DataTable table)
{
foreach (var row in table.Select())
{
dynamic x = new DynamicRow(row);
Console.WriteLine(string.Format("The Film {0}({1}) is rated as {2}",
x.Title, x.Year, x.Rating));
}
}

Microsoft propone como práctica sobrecargar la definición del método extensor AsDynamic para cada tipo que se quiera tratar en forma dinámica:

static dynamic AsDynamic(this DataRow x)
{
return new DynamicRow(x);
}

Si se adopta este convenio tenemos una tenemos una notación uniforme para convertir un objeto en dinámico, haciendo:

dynamic x = myDataRow.AsDynamic();

Con esto, el desarrollador que quisiera tratar un objeto de tipo DataRow como dinámico no estará obligado a conocer la existencia y el nombre del “tipo conversor” (DynamicRow en este caso), y podrá simplemente aplicar el método AsDynamic (que al ser un método extensor de DataRow le será mostrado por Intellisense).

La deuda con LINQ

Pero no se entusiasme demasiado el lector; lamentablemente, la maquinaria de LINQ aún no está preparada para actuar sobre una fuente de datos que produce datos de tipos que no sean estáticamente conocidos. El compilador de VS 2010 Beta 2 da un mensaje de error ante un código como el siguiente, alegando que los tipos dinámicos no se admiten en los árboles de expresiones lambda:

var q = from c in objectContext.CreateQuery[miTabla].AsDynamic()
where c.xmin > 100 && c.ymin > 100 &&
c.xmax < 900 && c.ymax < 900
select c;

Claro que para lograr esto no basta con una solución tan simple como la que hemos mostrado en el ejemplo de DynamicRow. Esto no sería suficiente para lograr toda la funcionalidad recogida hoy día en proveedores de LINQ como LINQ to SQL o LINQ to Entities (que además implementan funcionalidades adicionales como caché, manejo de concurrencia, coherencia y consistencia relacional, etc.). Esperamos que esto se incluya en el roadmap de las futuras versiones de .NET Framework. En el pasado PDC, Luca Bolognese, interrogado al respecto del porqué de la no inclusión de dynamic dentro de los árboles de expresiones (expression trees), insinuó que en esto se estaba trabajando como parte de una solución más general para tratar completamente la compilación como un servicio (compiler as a service).

Interoperabilidad con otros entornos

Aunque en .NET disponemos de un mecanismo de interoperabilidad con código nativo, esto no es suficiente ni cómodo de usar. También queremos interoperar con JavaScript, Office8, etc. El uso del tipado dinámico nos permite acceder y manipular objetos aplicándoles dinámicamente operaciones con la misma notación .NET, aunque tales objetos no “vivan” ni estén hechos para convivir en el mundo .NET.

Prototipado

Finalmente, otro posible escenario de aplicación del tipado dinámico es el desarrollo de prototipos. La peculiaridad de los prototipos es la rapidez con que necesitamos sean programados; en muy poco tiempo, un programador quiere lograr un señuelo de lo que supuestamente será una aplicación aún por hacer. En tales escenarios, donde en un inicio los modelos de datos aún no están concebidos, es importante poder armar “estructuras ligeras” que se puedan utilizar con prontitud y sin muchas restricciones de compilación, y con mucha funcionalidad pendiente de implementar.

Conclusiones

Con esta nueva propuesta de C# 4.0, los programadores .NET no tienen que renunciar a los buenos hábitos adquiridos con el tipado estático. No obstante, con el tipado dinámico vamos a poder escribir ahora código más sencillo en situaciones en las que antes teníamos que aplicar una notación mucho más compleja y extensa, por ejemplo usando reflexión.

Las capacidades que nos brinda el DLR para personalizar la resolución dinámica, como hicimos en el ejemplo de DynamicRow, pueden ser aprovechadas para interoperar con escenarios que no sean del todo estáticamente conocidos, como el ejemplo que mostramos para LINQ. Es poca aún la documentación publicada sobre el DLR y el espacio de nombres System.Dynamic, por lo que habrá que volver sobre este tema más adelante.

Las muy deseadas capacidades de brindar la compilación como un servicio, que ya han sido mostradas en algunos foros, pero sobre las cuales Microsoft aún no ha hecho ningún compromiso oficial, pudieran usarse combinadamente con estos recursos de tipado dinámico para desarrollar prototipos rápidos y para integrar DSL (lenguajes de dominio específico) con código C#. Esta es una línea de trabajo sumamente interesante.

Mario del Valle

Instructor de programación y desa rro llador del grupo WEBOO.

Manual