C#3.0, LINQ / Expresiones Lambda

LINQ - Language Integrated Query / Expresiones Lambda
Introducido en la versión 3.0 de .NET, LINQ nos permite realizar consultas similar a las de SQL en nuestro código.
Lambda es una forma de escribir funciones anónimas en el cual se lo suele usar para pasar con facilidad como argumentos y para crear delegados.
Todo esto combinado con el uso de los genéricos hace que el código sea simple.
Veamos un ejemplo de código con LINQ:
Ficha ficha = (from child in Children.OfType<Ficha>() where child.Name == "_1" select child).First<Ficha>() as Ficha;
La sintaxis es idéntica al SQL, en este caso necesitábamos extraer un elemento de tipo "Ficha" con el nombre "_1" de la propiedad "Children" que devuelve una colección de objetos (En Silverlight, "Children" es una propiedad que representa un contenedor de donde desprende los elementos gráficos que se muestra en pantalla).
Ahora ajustando el mismo código con una expresión Lambda:
Ficha ficha = Children .OfType<Ficha>() .Where(child => child.Name == "_1") .First<Ficha>();
o simplificandolo mas:
Ficha ficha = Children .OfType<Ficha>() .Single(child => child.Name == "_1");
Todo muy lindo pero el ejemplo que propuse no creo que sorprenda a los programadores Flash dado que a nivel funcional lo que quiero hacer es equivalente a "getChildByName". Osea en código AS3 seria:
var ficha:Ficha = this.getChildByName("_1") as Ficha;
Leer XML con Silverlight 2
Lo que sigue ahora, sí es impresionante, el ejemplo que propongo a continuación es con Silverlight 2 y se trata de leer un XML con LINQ.
Tengo el XML siguiente, sites.xml:
<?xml version="1.0" encoding="UTF-8"?> <main> <sites> <site name="Blog" link="http://www.nessy.com.ar/blog" thumb="thumb.blog.jpg" /> <site name="LinkedIn" link="http://www.linkedin.com/in/FranciscoRosales" thumb="thumb.linkedin.jpg" /> <site name="Twitter" link="http://www.twitter.com/nessy" thumb="thumb.twitter.jpg" /> </sites> </main>
En consecuencia tengo el objeto siguiente:
using System;
namespace NessyJackSL.model
{
public class Site
{
public string name { get; set; }
public string link { get; set; }
public string thumb { get; set; }
}
}
Y finalmente tengo la clase llamada JackData que se encargará de leer el XML:
using System;
using System.Net;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using NessyJackSL.util;
using NessyJackSL.model;
namespace NessyJackSL.data
{
public class JackData
{
public event EventHandler EVENT_DATA_READY;
public static Site[] sites;
public JackData()
{
try
{
WebClient client = new WebClient();
client.OpenReadAsync(new Uri("sites.xml", UriKind.Relative));
client.OpenReadCompleted += new OpenReadCompletedEventHandler(onComplete);
}
catch (Exception ex)
{
Log.w("JackData.Error > " + ex.Message);
}
}
private void onComplete(object sender, OpenReadCompletedEventArgs evt)
{
XDocument doc = XDocument.Load((Stream) evt.Result);
sites = (from site in doc.Descendants("site")
select new Site
{
name = site.Attribute("name").Value,
link = site.Attribute("link").Value,
thumb = site.Attribute("thumb").Value
}).ToArray();
EVENT_DATA_READY(this, new EventArgs());
}
}
}
Presten atención a lo que se hace en el código siguiente extraido de la clase JackData:
XDocument doc = XDocument.Load((Stream) evt.Result);
sites = (from site in doc.Descendants("site")
select new Site
{
name = site.Attribute("name").Value,
link = site.Attribute("link").Value,
thumb = site.Attribute("thumb").Value
}).ToArray();
Una vez cargado el XML sites.xml, estas pocas líneas de código efectúan las acciones siguientes:
recorre los nodos con nombre "site", crea un objeto asignándole el valor que proviene del atributo que le corresponde por cada nodo encontrado y se lo agrega al Array, al final devuelve un Array de Site.
Ahora también lo podemos hacer con la combinación de la expresión Lambada:
sites = doc
.Descendants("site")
.Select(
site => new Site
{
name = site.Attribute("name").Value,
link = site.Attribute("link").Value,
thumb = site.Attribute("thumb").Value
}
).ToArray();
Mi polémica afirmación es que no he visto esta simplicidad en ningún otro lenguaje de programación conocidos pero existen desarrollos en curso para adaptarlos a los lenguajes mas populares.
Las opciones para Java son Quare (http://quaere.codehaus.org/) y JLinq (http://www.hugoware.net/).
Para ActionScript 3 es GAIQL (http://g-unix.com/blog/1/2008/05/Actionscript-Intergrated-Query-Language-Preview-Release.cfm).
Para PHP se llama PHPLinq (http://phplinq.codeplex.com/).
Javascript parece tener su Lambda: http://alex.dojotoolkit.org/2009/05/on-js-lambdas/.
