martes, 10 de junio de 2008

C# es fácil (iv): Expresiones lambda

La inclusión de las expresiones lambda en C#, ha hecho que algunos empiecen a tener escalofríos y sudores fríos, recordando sus tiempos de estudiante de ingeniero informático y el cálculo lambda... Cuando Microsoft anunció, la incorporación de expresiones lambda en C# muchos se empezaron a preguntar si esto era el renacimiento de C# como lenguaje funcional. Al final, como suele suceder, no ha sido para tanto...

En definitiva podemos decir que las expresiones lambda son una sintaxis alternativa para los métodos anónimos (que aparecieron en C# 2.0, o sea Visual Studio 2005). Imaginemos el caso que queremos ordenar una lista, usando el método Sort. El mètodo Sort espera un delegate de tipo Comparison. Este delegate es un delegate genérico que espera dos argumentos de tipo T, y devuelve un int:

public delegate int Comparison<T>(T x,T y);

Si queremos ordenar una lista, usando un método anónimo, haríamos algo parecido a esto:

List<string> lista = new List<string>() { "Perro", "Gato", "Zorro" };

lista.Sort (delegate (string s1, string s2)

{

return s1.CompareTo(s2);

} );

Dentro de la llamada del método Sort, creamos el método anónimo (de tipo Comparison<string>).

Bien, pues básicamente las expresiones lambda son una sintaxis alternativa (muuucho más compacta), para hacer exactamente lo mismo. Fijaros como quedaría el código anterior usando expresiones lambda:

List<string> lista = new List<string>() { "Perro", "Gato", "Zorro" };

lista.Sort ( (x,y) => x.CompareTo(y));

Es una sintaxis mucho más compacta que "la clásica" de métodos anónimos, verdad??? ;-) Pues vamos a comentarla rápidamente...

El operador => es el operador lambda, y la sintaxis és param-list => valor_retorno siendo param-list una lista de parámetros (separados por comas), y valor_retorno una expresión que se evaluará y será el resultado de la expresión lambda.

Veamos otro ejemplo de como las expresiones lambda sustituyen (sintacticamente) a un método anónimo. Imaginemos el delegate:

public delegate T Updater<T> (T value);

Un delegate que toma un objeto de tipo T y devuelve otro del mismo tipo.

En la sintaxis estándard (C# 1.0 sin métodos anónimos) haríamos algo como:

Updater<int> pFoo = new Updater<int>(SumaUno);

donde SumaUno, seria un método definido como algo parecido a:

int SumaUno(int x) { return x + 1; }

Usando métodos anónimos (C# 2.0) la cosa nos queda como:

Updater<int> pFooAnonimo = delegate(int x) { return x + 10; };

Lo cual ya es más compacto que la sintaxis anterior... y usando las nuevas expresiones lambda, la cosa nos queda como:

Updater<int> pFooLambda = x => x + 50;

Más compacto... imposible, no??

Bueno... una cosilla debeis tener presente con las expresiones lambda... C# es un lenguaje fuertemente tipado, y por ello las expresiones lambda tienen tipo... Que nosotros no pongamos tipo en los parámetros de una expresión lambda, no significa que lo tengan, significa que el compilador debe poder deducirlos por el contexto.En este ejemplo que acabo de poner, el compilador deduce que "x" es de tipo int, porque estamos asignando la expresión lambda a un delegate que espera un parámetro de tipo int (y una expresión lambda siempre se asigna a un delegate, y es este delegate quien nos define el tipo de los parámetros). En el otro ejemplo que he expuesto antes (el de la llamada a Sort), el compilador puede deducir que los parámetros x e y son de tipo string, porque estoy llamando a Sort de una List<string> que por lo tanto me espera un delegate de tipo Comparison<string> que define dos parámetros de tipo string.

En resumen: las expresiones lambda son una nueva sintaxis (eso sí, mucho más compacta) para una funcionalidad que ya teníamos: los métodos anónimos en C#.

lunes, 2 de junio de 2008

El método de la burbuja (para ordenar listas, claro).

MMmm... analizando los logs de google analytics, he visto que mucha (mucha de la poca se entiende xD), que entra al blog, lo hace a través de una búsqueda relacionada con... el algoritmo de ordenamiento de la burbuja! Así, que bueno... me he decidido a escribir algo sobre este algoritmo... al menos los pocos que llegan por aquí, que se queden contentos!! ;)

Por quien no conozca este algoritmo, diré que se trata de una forma no muy eficiente de ordenar los elementos de una lista. Eso sí, al menos tiene dos ventajas: és un método sencillo y además es un método sencillo. Y en que consiste???

Pues bueno, supongamos una lista de números, desordenada... por ejemplo 32,4,35,1 y queremos ordenarla de menor a mayor. Para ello cojemos el primer par de elementos (32 y 4) y:

  • Si el segundo es menor que el primero los intercambiamos
  • En caso contrario, los dejamos tal cual.
  • Repetimos el procedimiento, ahora con el segundo y tercer elemento de la lista... hasta llegar al final.
  • Luego volvemos a repetir todo el procedimiento, pero hasta llegar al penúltimo elemento... luego repetimos, pero llegamos hasta el antepenúltimo elemento, y así sucesivamente, hasta tener la lista ordenada.

En nuestro ejemplo (en negrita el par de elementos que comparamos y en cursiva los elementos que quedan fuera de la comparación):

32, 4, 35,1 => 4,32,35,1 => 4,32,35,1 => 4,32,1,35 => Repetimos desde el inicio, pero sin contar el último elemento

4,32,1,35 => 4,32,1,35 => 4,1,32,35 => Repetimos desde el inicio, pero sin contar los dos últimos elementos:

4,1,32,35 => 1,4,32,35 => Fin del algoritmo. Lista ordenada.

Bueno... el código en C# seria algo así como sigue (adaptación del código que podeis encontrar en "la tecla de escape"):

static void Burbuja(List<int> lst)

{

int iaux;

for (int i = 0; i < lst.Count - 1; i++)

{

for (int j = 0; j < lst.Count - i - 1; j++)

{

if (lst[j] > lst[j + 1])

{

iaux = lst[j];

lst[j] = lst[j + 1];

lst[j + 1] = iaux;

}

}

}

}


Qué sencillo, no???? Pues bueno... vamos ahora a hacer que el método ordene, no solo listas de ints, si no listas de cualquier tipo... uno podría pensar que igual basta declarar el método genérico... Lamentablemente si declaramos el método como:

static void Burbuja<T>(List<T> lst)

{

T iaux = default(T);

// El resto todo igual que antes...


El método no compila... el compilador se queja diciendo: Operator '>' cannot be applied to operands of type 'T' and 'T'. Este error es debido a que los parámetros genéricos son tratados como de tipo object... y el operador > no está definido para tipos object. Además usar una clausula where, no nos sirve en este caso (ya que where nos permite indicar que el parámetro template debe satisfacer una determinada interfaz, pero los operadores siempre se declaran como static en C# y por lo tanto nunca pueden declararse en una interfaz).

Entonces... estamos atrapados? Pues no... la solución pasa por usar un parámetro extra en nuestro método Burbuja, que le indique como debe ordenar los elementos. Es decir, un parámetro que le indique a nuestra función Burbuja, que método debe usar (en lugar de operador '>') para determinar si un elemento es "mayor" que otro. Además, eso es incluso más lógico que usar el operador '>', puesto que imaginemos que tenemos una lista de perros... igual nos interesa ordenarlos por tamaño, pero quizá lo queremos hacer por raza o color del pelo... entonces si tenemos que pasar un parámetro que apunte a un método... necesitamos un delegate.

Así deberiamos declarar un delegate que fuese algo parecido a:

delegate int Comparador<T> (T a1, T a2);


En este caso asumiremos que el delegate nos devuelve 1 si a1 es "mayor" que a2 y -1 si es al revés.

Y usar nuestro método Burbuja como sigue:

delegate int Comparador<T> (T a1, T a2);

class Program

{

static int ComparaDoubles(double d1, double d2)

{

if (d1 == d2) return 0;

return d1 > d2 ? 1 : -1;

}

static void Main(string[] args)

{

List<double> lista = new List<double>() { 32.3, 4.1, 35.2, 1.09 };

Burbuja(lista, new Comparador<double>(Program.ComparaDoubles));

}

static void Burbuja<T>(List<T> lst, Comparador<T> comparador)

{

T iaux = default(T);

for (int i = 0; i < lst.Count - 1; i++)

{

for (int j = 0; j < lst.Count - i - 1; j++)

{

if (comparador(lst[j], lst[j + 1]) == 1)

{

iaux = lst[j];

lst[j] = lst[j + 1];

lst[j + 1] = iaux;

}

}

}

}

}


Ale... solo teneis que cambiar el método al que apunta el delegate y podeis ordenar lo que os de la gana!

Bueno... y ahora que os he soltado el rollo... dos cosillas:

  1. El framework ya define un delegate como nuestro "Comparador", y se llama Comparison.
  2. La clase List<T> tiene un método Sort, que espera como parámetro... un delegate de tipo Comparison... :)

O sea que si quereis ordenar listas, lo mejor es algo del estilo:

lista.Sort (delegate (double d1, double d2)

{

if (d1 == d2) return 0;

return d1 > d2 ? 1 : -1;

} );


Bueno... espero que al menos los que aterrizais por aquí buscando información sobre el método de la burbuja... os haya servido este post!

Nos leemos! ;)

lunes, 26 de mayo de 2008

Porque no hay referencias const en c#?

Jejejeee... los que conozcais C++ ya sabreis por donde voy... para los demás, os cuento...

En C++ se puede declarar un puntero (o una referencia, que en C++ no es lo mismo que un puntero, pero tampoco importa esto ahora) como const. Con eso le indicamos al compilador que el método que recibe el puntero no puede modificar los datos apuntados por éste.
Si la referencia apunta a un tipo simple (sin ánimo de ofender) como int o char, pues el compilador ya sabe lo que es "modificar" los datos... Por ejemplo, esto en C++ no compia:


void foo (const int* pValor)

{

*pValor = 10;

}

El compilador se queja con un claro mensaje de error (lo que ya es raro viniendo de C++): 'pValor' : you cannot assign to a variable that is const.

En el caso de que el puntero apunte a una clase... como sabe el compilador si un método modifica los datos de la clase? Imaginemos la siguiente clase:

class Perrito

{

int edad;

public:

inline void SetEdad(int anyos) { edad = anyos;}

inline int GetEdad() { return edad;}

};

Ahora imaginemos una función que trabaja con Perritos:

void foo (Perrito* pDog)

{

pDog->GetEdad();

}

Vale... la función es un poco raquítica, pero servirá... Esta funcion NO modifica el estado del objeto Perrito que se le pasa, por eso, si queremos podemos indicarlo expresamente, añadiendo const al parámetro pDog:

void foo (const Perrito* pDog) { ... }

Con esto le indicamos al compilador y al usuario de nuestra función, que foo NO modifica el estado del objeto Perrito que se le pase... Si estais compilando este código, no lo hagáis... no compila (y esta vez el mensaje ya es un mensaje típico de C++: 'Perrito::GetEdad' : cannot convert 'this' pointer from 'const Perrito' to 'Perrito &').

Entonces??? Donde está la gracia? Si añado const y el código no compila.... Bueno, no desesperemos, la gracia de todo está en que la clase Perrito es incompleta. Le falta indicar al compilador cuales son las funciones que NO modifican el estado del objeto. En concreto en este caso sabemos que la función GetEdad no modifica el estado del Perrito, mientras que la función SetEdad sí... entonces, en la clase Perrito cambiamos la definición de GetEdad:

inline int GetEdad() const { return edad;}

Ole! Ahora nuestro código si que compila: foo declara que NO modifica el estado del Perrito que recibe y, por ello el compilador sólo le va a dejar llamar a funciones declaradas explícitamente como const en la clase... si añado una llamada a SetEdad dentro de foo, entonces el compilador se me va a quejar ('Perrito::SetEdad' : cannot convert 'this' pointer from 'const Perrito' to 'Perrito &').

Bueno... así a grandes rasgos es como funciona el mecanismo de punteros (o referencias) const en C++ (luego hay ciertos añadidos como mutable, pero vamos lo básico es esto). Notar también que una función puede devolver un puntero const y entonces es quien recoge este valor devuelto el que no puede modificar el estado de los datos apuntados por el puntero.

Pues, ahora repito la pregunta: porque nunca se ha añadido este mecanismo en C#??? Para empezar nos ahorraríamos clases como la ReadOnlyCollection (mis funciones podrían recibir o devolver una const List<T>, p.ej.). De verdad... si alguien tiene alguna idea de porque nunca se ha añadido esta característica en C# que me lo diga!!

Saludos!

jueves, 22 de mayo de 2008

C# es fácil (iii): Métodos de extensión.

Bueno... vamos a seguir las entregas de C# es fácil, hablando de otras de las novedades de C# 3.0: los métodos de extensión.

En realidad los métodos de extensión no son más que la posibilidad de usar la sintaxis para llamar a un método de un objeto (vamos, el objeto.metodo() de toda la vida), para llamar a un método estático, definido en otra parte. El hecho de que el compilador nos permita usar la sintaxis objeto.metodo() nos crea la ilusión, de que el método de extensión pertenece a la clase de la cual es instancia el objeto. Pero no: el método es un simple y corriente método estático, de los de toda la vida.

Vamos a ver un ejemplo... mirad el siguiente código:

public static class Extensions


{


public static string Left(this string s, int num)


{


if (s == null) return null;


if (num <= 0) return string.Empty;


if (num <= s.Length) return s.Substring(0, num);


return s;


}


}


En él definimos una clase estática (Extensions) que contiene un método llamado Left. Fijaos en la declaración del método... en el primer parámetro lleva el modificador this. Esto lo convierte en un método de extensión. Ahora yo puedo hacer lo siguiente, desde cualquier otra parte de mi código:

string s = "Burbujas en .NET";


string s2 = s.Left(8);


Fijaos que el método que yo he definido, puedo usarlo como si fuese un método más del objeto s, que es un objeto string. Pero... que hace internamente el compilador? Pues llama al método Extensions.Left y le pasa como primer parámetro (el que tiene el this) el valor del objeto sobre el cual se ha invocado el método (en este caso mi string s).

Eso son en resumen los métodos de extensión... pero ahora unos cuantos puntos a tener claros:

  1. Los métodos de extensión NO forman parte de la clase que "extienden". Es decir, en nuestro ejemplo el método Extensions.Left, no puede acceder a los métodos protected de la clase string.

  2. Los métodos de extensión deben definirse en una clase marcada como static (y por lo tanto deben ser todos ellos static).

  3. Los métodos de extensión pueden invocarse sobre una referencia nula y no da una excepción (simplemente el método recibe null en el parámetro).

  4. Igualmente se pueden definir métodos de extensión cuyo parámetro marcado como this, sea una clase sealed. Esto nos da la ilusión de estar "extendiendo" una clase sealed.

  5. Igualmente se pueden definir métodos de extensión cuyo parámetro marcado como this sea una interface.

  6. Los métodos de extensión tambien son métodos "normales", es decir pueden llamarse en su forma... digamos tradicional. Los siguiente funcionaria:

    string s3 = Extensions.Left("Hola", 2);


  7. Los métodos de extension pueden ser genéricos, y eso vamos a verlo ahora con más detalle

Mirad el siguiente código:

public static class Extensions


{


public static string ToUpperString<T>(this T p)


{


if (p == null) return null;


return p.ToString().ToUpper();


}


}


Definimos un método de extension que funciona para cualquier objeto de cualquier tipo. Recordad que C# infiere los tipos de parámetro genéricos, o sea que las siguientes llamadas funcionan:

string s = "hola".ToUpperString();


int i = 100;


string s2 = i.ToUpperString();

En la primera llamada el compilador infiere que el tipo genérico es "string" y llama a Extensions.ToUpperString<string>(), mientras que en el segundo caso, infiere que es "int" (Int32) y llama Extensions.ToUpperString<Int32>().

En fin... eso es todo lo básico de métodos de extensión... como podeis observar no se trata más que de una treta del compilador para hacernos creer que un método está definido en una clase, cuando realmente está definido como static en otra.

Ah sí!! Y me olvidaba... ojo con el uso desmesurado de los métodos de extensión! No son y no deben ser un sustituto para la herencia o métodos normales de clase. Tienen un par de inconvenientes que hay que señalar:

  1. No pueden acceder a métodos protected de la clase que "extienden".

  2. Para poder usarlos el compilador debe poder encontrar la clase static que los contiene. Eso significa que debemos tener una referencia al assembly que contiene dicha clase static y (generalmente) el using del namespace en el cual está definida la clase.

  3. Complica el seguimiento del código por parte de terceros, porque cuando vemos objeto.metodo() no nos basta con mirar la clase (y superclases) de objeto, si no que además debemos tener presente todos los posibles métodos de extensión.

  4. Si el compilador se encuentra que puede llamar a dos métodos de extensión (vamos, que dos clases distintas me definen un método de extensión que se llama igual y ambos aceptan como parámetro this un objeto de la misma clase), el compilador se quejará con un error... exceeeeeeeeeepto si uno de los métodos de extensión es genérico, en cuyo caso el compilador a la chita callando... llamará al otro.

  5. En caso de colisión los métodos de extensión tienen menos prioridad que los métodos propios de una clase. Es decir en el siguiente código:

    public class Complex


    {

    public string ToUpperString()


    {

    return "ToUpperString de Complex";

    }


    }


    public static class Extensions

    {

    public static string ToUpperString<T>(this T p)

    {

    if (p == null) return null;

    return p.ToString().ToUpper();

    }

    }


    Una llamada a new Complex().ToUpperString(); me devolverá "ToUpperString de Complex": es decir me invocará al método propio de la clase en lugar del método de extensión.

Bueno... ahora creo que sí ya lo hemos aclarado más o menos todo... :) En resumen: usadlos con prudencia!

Saludos!

miércoles, 21 de mayo de 2008

Charla en catdotnet

Este viernes (16 de mayo) he tenido el honor de presentar una pequeña demo en una charla de catdotnet, el grupo de usuarios de .NET de la catalunya central. La charla fue en Igualada y se impartieron dos pequeñas sesiones:

  1. Em primer lugar intervine yo, y bajo el título "Qui diu que .NET 3.0 és dificil?" (¿Quien dice que .NET 3.0 es difícil?), presenté una demo práctica de unos 45 minutos en los cuales montamos una aplicación web que mostraba imágenes de una base de datos. Luego creamos una librería de servicios WCF, que se conectaba a la BBDD y devolvia las imágenes de un determinado usuario, y consumimos esta librería de servicios en una aplicación WPF.

  2. En segundo lugar fue Lleonard Del Río quien mostró una demo de Workflow Foundation y explicó sus principales características.

Ambas sesiones fueron totalmente prácticas (vamos, sin powerpoint, sólo con Visual Studio... como tiene que ser! xD).

Cuando esté el código disponible en la página de catdotnet, os aviso! :)

Saludos!

C# es fácil (ii): Usos de var

En el post anterior de C# es fácil, hemos hablado un poco sobre los tipos anónimos. Ahora me gustaría comentaros algunas cosillas de la palabra clave var. Recordemos que var viene a significar: declara la variable del tipo que se corresponda a la expresión de la derecha de la asignación.

Lo que debes tener presente de var es que:

  1. Debes declarar e inicializar la variable. Es decir: var i; no compila ya que no hay expresión de la que inferir el tipo de la variable i. Recuerda que C# es un lenguaje fuertemente tipado.

  2. var se resuelve en tiempo de compilación, nunca de ejecución. Es decir si tengo:

    class Animal { }


    class Perro : Animal { }


    y entonces hago:

    Animal animal = new Perro();


    var perro = animal;


    la variable perro se declarará de tipo Animal.

  3. No puedes devolver var:

    static var foo()

    {

    return new { X = 10, Y = 20 };

    }


    Este código no compila, con el mensaje de error (The contextual keyword 'var' may only appear within a local variable declaration). Es una lástima no poder devolver var porque esto nos impide devolver (fácilmente) tipos anónimos entre métodos. De hecho, se considera que los tipos anónimos tienen un ámbito local.

  4. Declarar una variable usando var o usando el nombre de la clase que realmente se corresponde no tiene ninguna diferencia. El código MSIL generado por el compilador es el mismo en ambos casos, o sea que usar var es una decisión personal (excepto cuando hay tipos anónimos por en medio, que entonces debe usarse sí o sí).

Saludos!

lunes, 19 de mayo de 2008

C# 3.0 es fácil (i): tipos anónimos

Bueno... con este post empezamos una (pequeña) serie de posts para desgranar las novedades de C# 3.0 (o sea, el C# de VS 2008). Veremos las novedades del lenguaje y como estas se combinan para dar soporte a LINQ... y para empezar, que mejor que tipos anónimos?

Ahora en C# podemos hacer algo como:
var i = 0;
Cuando la gente ve esto, generalmente tiene dos tipos de reacciones:
  1. A los desarrolladores con experiencia en Javascript, o otros lenguajes dinámicamente tipados. se les humedecen los ojos de la emoción de pensar que por fin C# es un lenguaje dinámicamente tipado.
  2. A los desarrolladores con experiencia en VB6 también se les humedecen los ojos, pero en este ocasión es de pánico, al pensar que una cosa parecida a Variant vuelve...
Pues no... ni C# es tipado dinámicamente, ni mucho menos, algo parecido a Variant vuelve para recordarnos nuestras peores pesadillas...
... pues entonces, que significa la palabra clave var?

En C# var significa: declara la variable del tipo correspondiente al tipo de la expresión que se halle a la derecha de la asignación...
O dicho de otro modo:
var i = 0;

es equivalente a:
int i = 0;


Y en este caso equivalente significa lo mismo, exactamente lo mismo.
Si no os lo creeis, probad a compilar esto:
var i = 0;
i = "hola";

Vereis como el compilador se quejará con un claro: Cannot implicitly convert type 'string' to 'int'

Ok, ahora que tenemos claro que significa var, para que lo han añadido al lenguaje? Uno puede pensar que es para evitar que tecleemos tanto... cierto que de var a int no van muchos carácteres, pero de var a Dictionary<MiClase, MiOtroPedazoClase>
, pues ya van unos cuantos... Pero no, nos los tiros no van por ahí... los caminos de Redmond son mucho más elevados. La incorporación de la palabra clave var viene dada por la aparición de los tipos anónimos.
Y que es un tipo anónimo? Pues como su nombre indica, una clase... sin nombre. Y como puede no tener nombre una clase, si necesito su nombre para declararla usando class? Pues porque los tipos anónimos se declaran a la vez que se construye un objeto de este tipo. Algo parecido a los métodos anónimos que los declaramos a la vez que construimos un delegado.
Para declarar un tipo anónimo y construir a la vez un objeto de este tipo de usa la palabra clave new (eso tiene al menos lógica, no? xD).
Observad el siguiente código:

string data = "Francesc Eiximenis";
var eiximenis = new { Nombre = data.Split(' ')[0], Apellido = data.Split(' ')[1] };

Estamos creando un tipo anónimo, con dos propiedades (Nombre y Apellido) y a la vez estamos creando (e inicializando) un objeto de este tipo, y asignándolo a la variable eiximenis. Fijaos en el uso de var para declarar la variable... puesto que si no seria imposible hacerlo (no hay ninguna clase Eiximenis!).
El uso clásico de los tipos anónimos consiste en casos como este: queremos agrupar dos o tres datos en un objeto, pero nos da pereza crear una clase nueva... Pues nada... solucionado!

Pero vamos a hacer cosillas un poco... más divertidas y es que aunque Eiximenis por si sólo ya da para mucho, que pasa si quiero crear pongamos una lista de objetos de este tipo y luego recorrerla? Vamos a verlo...
List<string> _strs = new List<string>();
_strs.Add("Francesc Eiximenis");
_strs.Add("Ramon Llull");
_strs.Add("Bernat Metge");
ArrayList escritores = new ArrayList();
foreach (string s in _strs)
{
string[] tokens = s.Split(' ');
escritores.Add(new { Nombre = tokens[0], Apellido = tokens[1] });
}

Con este código creo tres objetos de mi tipo anónimo y los añado a un ArrayList... Y como se que tengo tres objetos de un tipo anónimo, y no tres objetos de tres tipos anónimos (con las mismas propiedades?)... pues porque el compilador de C# no es tonto del todo y es capaz de reaprovechar tipos anónimos si declaramos dos o más objetos anónimos con las mismas propiedades... cosa que veremos que es realmente interesante.

Ok... pues eso: tengo el ArrayList escritores con tres objetos, y puedo asegurar que los tres son del mismo tipo anónimo... y ahora quiero recorrer este ArrayList...
foreach (var escritor in escritores)
{
Console.WriteLine("Nombre: " + escritor.Nombre);
}

Ajá!!! Listos habreis pensado... pues no :( Este código que acabo de poner... no compila. Y por que? Pues porque var se resuelve en tiempo de compilación, no en tiempo de ejecución... y aunque la ArrayList escritores contenga objetos de mi tipo anónimo, la clase ArrayList define que su enumerador devuelve Object, así que la variable escritor es una referencia de tipo object. Encima como el tipo es anónimo no puedo hacer un cast de escritor al tipo real porque no tiene nombre!
Estamos en un callejón sin salida? Por los pelos... pero no.

La solución pasa por generar una clase que me defina su enumerador al tipo anónimo... en definitiva en lugar de una ArrayList, usar una List<T>, siendo el parámetro genérico T nuestro tipo anónimo...

---- un incómodo silencio va aquí ----

... valeeeeeeeeeeeeee... me habeis pillado!!! Si no tenemos nombre de clase, como vamos a hacer:



List<T> escritores; // Que pongo en lugar de T si no tengo nombre de clase?

Pues por suerte tenemos una posibilidad de hacerlo, aprovechandonos del hecho de que C# es capaz de inferir los tipos genéricos de un método.
Recordad que si tengo el siguiente método:
public static Type TypeOf(T type)
{
return type.GetType();
}

Entonces, gracias a la inferencia de tipos genéricos, estas dos llamadas son equivalentes:
TypeOf<int>(10);
TypeOf(10);


La primera llamada es la tradicional (pasamos el tipo genérico). En la segunda llamada el tipo genérico se infiere a partir del tipo del parámetro.

Entonces si definimos este método:
public static List<T> ListOfType(T type)
{
return new List<T>();
}

Este método, dado un parámetro de un tipo nos devuelve una referencia a una List preparada para contener referncias de este tipo:
List<string> s = ListOfType<string>(string.Empty);

Y aprovechandonos de la inferenncia de tipos genéricos:
List<string> s = ListOfType(string.Empty);

Y si usamos var:
var s = ListOfType(string.Empty);

Todas estas llamadas son equivalentes, y en los tres casos s es una List<string>
. Nos vamos acercando, porque entonces...

var escritores = ListOfType(new { Nombre = string.Empty, Apellido = string.Empty });
foreach (string s in _strs)
{
string[] tokens = s.Split(' ');
escritores.Add(new { Nombre = tokens[0], Apellido = tokens[1] });
}
foreach (var escritor in escritores)
{
Console.WriteLine("Nombre: " + escritor.Nombre);
}

Ya lo tenemos!!!! Fijaos que el truco es declarar la variable escritores, pasándole un objeto de mi tipo anónimo... y eso funciona porque, si os acordáis, os comenté que el compilador de C# reaprovecha el tipo anónimo. Por suerte, porque si cada vez me crease un tipo anónimo distinto esto no funcionaria (el primer Add sobre escritores me petaría con un error de conversión).

Saludos!!!