143
Introducción a los generics en C# Comenzaremos hablando de los generics en el lenguaje C#, que son el mecanismo de implementación de clases parametrizadas. Los generics son el mecanismo de implementación de clases parametrizadas introducido en la versión 2.0 del lenguaje C#. Una clase parametrizada es exactamente igual a una clase de las habituales, salvo por un pequeño detalle: su definición contiene algún elemento que depende de un parámetro que debe ser especificado en el momento de la declaración de un objeto de dicha clase. Esto puede resultar extremadamente útil a la hora de programar clases genéricas, capaces de implementar un tipado fuerte sin necesidad de conocer a priori los tipos para los que serán utilizadas. ¿Confuso? Mejor lo vemos con un ejemplo. Sabemos que un ArrayList es un magnífico contenedor de elementos y que, por suerte o por desgracia, según se vea, trabaja con el tipo base object. Esto hace que sea posible almacenar en él referencias a cualquier tipo de objeto descendiente de este tipo (o sea, todos), aunque esta ventaja se torna inconveniente cuando se trata de controlar los tipos de objeto permitidos. En otras palabras, nada impide lo siguiente: ArrayList al = new ArrayList(); al.Add("Siete caballos vienen de Bonanza..."); al.Add(7); al.Add(new String('*', 25)); // 25 asteriscos Esto puede provocar errores a la hora de recuperar los elementos de la lista, sobre todo si asumimos que los elementos deben ser de un determinado tipo. Y claro, el problema es que el error ocurriría en tiempo de ejecución, cuando muchas veces es demasiado tarde:

Curso Linq

Embed Size (px)

DESCRIPTION

Curso Linq

Citation preview

Page 1: Curso Linq

Introducción a los generics en C# Comenzaremos hablando de los generics en el lenguaje C#, que son el mecanismo de implementación de clases parametrizadas.

Los generics son el mecanismo de implementación de clases parametrizadas introducido en la versión 2.0 del lenguaje C#. Una clase parametrizada es exactamente igual a una clase de las habituales, salvo por un pequeño detalle: su definición contiene algún elemento que depende de un parámetro que debe ser especificado en el momento de la declaración de un objeto de dicha clase.

Esto puede resultar extremadamente útil a la hora de programar clases genéricas, capaces de implementar un tipado fuerte sin necesidad de conocer a priori los tipos para los que serán utilizadas. ¿Confuso? Mejor lo vemos con un ejemplo.

Sabemos que un ArrayList es un magnífico contenedor de elementos y que, por suerte o por desgracia, según se vea, trabaja con el tipo base object. Esto hace que sea posible almacenar en él referencias a cualquier tipo de objeto descendiente de este tipo (o sea, todos), aunque esta ventaja se torna inconveniente cuando se trata de controlar los tipos de objeto permitidos. En otras palabras, nada impide lo siguiente:

ArrayList al = new ArrayList();al.Add("Siete caballos vienen de Bonanza...");al.Add(7);al.Add(new String('*', 25)); // 25 asteriscosEsto puede provocar errores a la hora de recuperar los elementos de la lista, sobre todo si asumimos que los elementos deben ser de un determinado tipo. Y claro, el problema es que el error ocurriría en tiempo de ejecución, cuando muchas veces es demasiado tarde:foreach (string s in al){  System.Console.WriteLine(s);}

Efectivamente, se lanza una excepción indicando que "No se puede convertir un objeto de tipo 'System.Int32' al tipo 'System.String'". Lógico.

Obviamente eso se puede solucionar fácilmente, por ejemplo creando nuestra propia colección partiendo de CollectionBase (o similar) y mostrar métodos de acceso a los elementos con tipado fuerte, o bien, usando delegación, crear una clase de cero que implemente interfaces como IEnumerable en cuyo interior exista una colección que es la que realmente realiza el trabajo.

En cualquier caso, es un trabajazo, puesto que por cada clase que queramos contemplar deberíamos crear una clase específica, tal y como se describe en el párrafo anterior.

Page 2: Curso Linq

Y aquí es donde los generics entran en escena. El siguiente código declara una lista de elementos de tipo AlgoComplejo:

List<AlgoComplejo> lista = new List<AlgoComplejo>();AlgoComplejo algo = new AlgoComplejo(); lista.Add(algo);lista.Add(new AlgoComplejo());lista.Add("blah"); // ¡Error en compilación!

Con esta declaración, no será posible añadir a la lista objetos que no sean de la clase indicada, ni tampoco será necesario realizar un cast al obtener los elementos, pues serán directamente de ese tipo.

Es interesante ver la gran cantidad de clases genéricas para el tratamiento de colecciones que se incorporaron con la versión 2.0 del framework en el espacio de nombres System.Collections.Generic, y su amplia utilización a lo largo del marco de trabajo.

Creación de clases genéricasEn los ejemplos anteriores hemos visto cómo utilizar las clases genéricas proporcionadas por el framework, pero, ¿y si queremos nosotros crear una clase genérica propia? Veremos que es muy sencillo.

Vamos a desarrollar un ejemplo completo donde podamos ver las particularidades sintácticas y detalles a tener en cuenta. Crearemos la clase CustodiadorDeObjetos, cuya misión es almacenar un objeto genérico y permitirnos recuperarlo en cualquier momento. Básicamente, construiremos una clase con una variable de instancia y un getter y setter para acceder a la misma, pero usaremos los generics para asegurar que valga para cualquier tipo de datos y que el objeto introducido sea siempre del mismo tipo que el que se extrae:

public class CustodiadorDeObjetos<T>{  private T objeto;  public T Objeto  {    get { return objeto; }    set { this.objeto = value; }  }}

Como podemos ver, en la propia definición de la clase indicamos que ésta será una plantilla que recibirá como parámetro genérico un tipo al que hemos llamado T en el ejemplo anterior.

Se puede apreciar cómo hemos declarado un miembro privado llamado objeto, de tipo T, al que se puede acceder a través del correspondiente getter y setter. El tipo concreto sobre el

Page 3: Curso Linq

que actuaremos se definirá en el momento de la instanciación de un objeto, puesto que habrá que indicarlo expresamente:

// Crea un custodiador de strings...CustodiadorDeObjetos<string> cs = new CustodiadorDeObjetos<string>();// Creamos un custodiador de intsCustodiadorDeObjetos<int> ci = new CustodiadorDeObjetos<int>();// Creamos un custodiador de CosasCustodiadorDeObjetos<Cosa> cp = new CustodiadorDeObjetos<Cosa>();

De esta forma, evitamos tener que crear clases específicas para cada tipo de datos con el que necesitemos trabajar, ahorrándonos muchísimo esfuerzo y manteniendo todas las ventajas que el tipado fuerte nos ofrece.

Y para que os hagáis una idea del potencial de esta técnica, pensad que si no existiera la genericidad (como ocurría en versiones anteriores del lenguaje), nos veríamos obligados a implementar clases específicas como las siguientes:

public class CustodiadorDeStrings{  private string objeto;  public string Objeto  {    get { return objeto; }    set { this.objeto = value; }  }}public class CustodiadorDeCosas{  private Cosa objeto;  public Cosa Objeto  {    get { return objeto; }    set { this.objeto = value; }  }}// ... etc.

El siguiente código muestra la utilización de la nueva clase genérica CustodiadorDeObjetos que definimos con anterioridad:

CustodiadorDeObjetos<string> cs = new CustodiadorDeObjetos<string>();cs.Objeto = "Hola"; // Asignamos directamentestring s = cs.Objeto; // No hace falta un cast,    // puesto que Objeto es de tipo string

cs.Objeto = 12; // Error en compilación,

Page 4: Curso Linq

    // Objeto es de tipo stringCustodiadorDeObjetos<int> ci = new CustodiadorDeObjetos<int>();ci.Objeto = 12; // Asignamos directamenteint i = cs.Objeto; // No hace falta un cast, pues Objeto es int

cs.Objeto = "Hola"; // Error en compilación,    // Objeto es de tipo int

Restricción de tipos en genericsUna particularidad interesante en la declaración de los generics en C# es la posibilidad de establecer limitaciones en los tipos utilizados como parámetros de las plantillas. Aunque resulte paradójico, el propio lenguaje facilita la creación de clases genéricas que no lo sean tanto, lo cual puede resultar realmente útil en múltiples escenarios.

Y para verle el sentido a esto, utilicemos el siguiente ejemplo, aparentemente correcto:

public class Seleccionador<T>{  public T Mayor(T x, T y)  {    int result = ((IComparable)x).CompareTo(y);    if (result > 0)      return x;    else      return y;    }}

Se trata de una clase genérica abierta, cuya única operación (Mayor(...)) permite obtener el objeto mayor de los dos que le pasemos como parámetros. El criterio comparativo lo pondrá la propia clase sobre la que se instancie la plantilla: los enteros serán según su valor, las cadenas según su orden alfabético, etc.

A continuación creamos dos instancias partiendo de la plantilla anterior, y concretando el generic a los tipos que nos hacen falta:

Seleccionador<int> selInt = new Seleccionador<int>();Seleccionador<string> selStr = new Seleccionador<string>();

Estas dos instanciaciones son totalmente correctas, ¿verdad? Si después de ellas usamos el siguiente código:

Console.WriteLine(selInt.Mayor(3, 5));Console.WriteLine(selStr.Mayor("X", "M"));

Page 5: Curso Linq

Obtendremos por consola un 5 y una X. Todo perfecto; aparece, para cada llamada, la conversión a cadena del objeto mayor de los dos que le hayamos enviado como parámetros.

El problema aparece cuando instanciamos la clase genérica para un tipo que no implementa IComparable, que se utiliza en el método Mayor() para determinar el objeto mayor de ambos. En este caso, se lanza una excepción en ejecución indicando que el cast hacia IComparable no puede ser realizado, abortando el proceso. Por ejemplo:

public class MiClase // No es comparable{}

[...]Seleccionador<MiClase> sel = new Seleccionador<MiClase>();MiClase x1 = new MiClase();MiClase x2 = new MiClase();Console.WriteLine(selString.Mayor(x1, x2)); // Excepción,    // no son    // comparables!

Una posible solución sería, antes del cast a IComparable en el método Mayor(), hacer una comprobación de tipos y realizar la conversión sólo si es posible, pero, ¿y qué hacemos en caso contrario? ¿devolver un nulo? La pregunta no creo que tenga una respuesta sencilla, puesto que en cualquier caso, se estarían intentado comparar dos objetos que no pueden ser comparados.

La solución óptima, como casi siempre, es controlar en tiempo de compilación lo que podría ser una fuente de problemas en tiempo de ejecución. La especificación de C# incluye la posibilidad de definir constraints o restricciones en la declaración de la clase genérica, limitando los tipos con los que el generic podrá ser instanciado. Y, además, de forma bastante simple, nada más que añadir en la declaración de la clase Seleccionador la siguiente cláusula where:

public class Seleccionador<T>  where T: IComparable // !Sólo permitimos comparables!{  public Tipo Mayor(Tipo x, Tipo y)  [...]

Existen varios tipos de restricciones que podemos utilizar para limitar los tipos permitidos para nuestros tipos genéricos:

where T: struct, indica que el argumento debe ser un tipo valor. where T: class, indica que T debe ser un tipo referencia. where T: new(), fuerza a que el tipo T disponga de un constructor público sin parámetros;

es útil cuando desde dentro de algún método de la clase se pretende instanciar un objeto del mismo.

Page 6: Curso Linq

where T: nombredeclase, indica que el tipo T debe heredar o ser de dicha clase. where T: nombredeinterfaz, T deberá implementar el interfaz indicado. where T1: T2, indica que el argumento T1 debe ser igual o heredar del tipo, también

parámetro genérico de la clase, T2.

Estas restricciones pueden combinarse, de forma que si queremos que un parámetro genérico se ciña a varias de ellas, simplemente las separamos por coma en la cláusula where:

public class Seleccionador<T>  where T: IComparable, new () // Sólo permitimos comparables,    // instanciable sin parámetros

Estas informaciones se completarán en el siguiente artículo en el que hablaremos de los Métodos genéricos en C#.

Page 7: Curso Linq

Pensando en GenericsDar el salto a los generics de .Net 2.0 supone un cambio en la forma de pensar. Como dicen en inglés, un "mind shift". En este artículo voy a tratar de explicar los generics mediante reglas que hagan fácil el proceso de detectar cuando se pueden usar y de qué manera. Si bien es cierto que generics no es ya nada nuevo, aún hay mucha gente que sigue con .Net 1.1. Ahora que están trabajando en .Net 4.0, es buen momento para irse actualizando.

Me voy a basar en el código fuente de mi propio frameworks DesktopRails y en ejemplos del framework CSLA.

¿Qué son los Generics?

Generics es algo así como el equivalente en .Net a las templates de C++, con unas cuantas diferencias. En realidad son más potentes puesto que el compilador de C# es más avanzado. Cuando vemos un código que usa los símbolos "<>" como el siguiente, sabemos que se trata de generics:

1. List<int> numbers = new List<int>();

Generics para colecciones

El uso más claro de generics es en colecciones de elementos. Con .Net 1.1 usábamos la clase ArrayList para disponer de arrays de elementos de cualquier tipo, puesto que ArrayList permite introducir objetos de tipo System.Object y en .Net todos los objetos heredan de esa clase. Entonces si necesitamos una lista de cadenas haríamos lo siguiente:

1. ArrayList myList = new ArrayList();2. myList.Add("this is a test");3. string firstItem = (string)myList[0];

En éste código vemos cómo se introducen elementos en el vector y cómo se extraen. Internamente el runtime toma el elemento como un System.Object aunque es un string, haciendo una conversion que llaman "boxing", empaquetado. A la hora de extraer el elemento y poderlo manipular, el runtime hace "unboxing" cuando se lo indicamos con la versión de tipo (typecast). Esto tiene dos desventajas:

1. La primera es el rendimiento. Se ha demostrado que la eficiencia es muchisimo mayor con generics porque como veremos a continuación, evitan el boxing-unboxing.

2. La segunda es que podemos cometer errores que sólo se descubrirán en tiempo de ejecución. Si el lugar donde el elemento se introduce en el vector está lejos del lugar donde se extrae, el programador podría intentar hacer el typecast a un tipo que no es el correcto. El compilador no puede detectar ese error y es en tiempo de ejecución cuando se produciría la excepción.

Page 8: Curso Linq

Con generics existen clases en System.Collections.Generic que sirven para el mismo propósito. Esta sería la alternativa al código anterior:

1. List<string> myList = new List<string>();2. myList.Add("this is a test");3. string firstItem = myList[0];

Si en lugar de declarar firstItem como string hubiesemos puesto int, el compilador hubiese dado un error. Además, VisualStudio y MonoDevelop (IDEs) son capaces de usar autocompletado  o intellisense para recordarnos que el tipo es string, con lo cual es posible que nisiquiera lleguemos a cometer el error.

Forma de detectar el uso de generics: Cada vez que tenemos una colección y estamos haciendo un typecast, podemos darnos cuenta de que se puede reemplazar ese código por una colección generica.

Generics para relaciones fuertemente tipadas

Ahora vamos a ver usos más complejos de generics, aunque en realidad cuando se adquiere esta forma de pensar, es fácil de escribir las clases genericas. Usemos como ejemplo una clase Presenter, que se encarga de pintar vistas en la pantalla. Las vistas son de tipo IMyView. La relación entre Presenter y las instancias de IMyView es clara. Si no tuviésemos generics el código sería algo como esto:

1. public interface IMyView2. {3. string BackgroundColor {get; set;}4. }5.  6. public class SomeView : IMyView7. {8. private string _bgcolor = String.Empty;9.  10. public string BackgroundColor11. {12. get13. {14. return _bgcolor;15. }16. set17. {18. _bgcolor = value;19. }20. }21. }22.  23. public class Presenter24. {25. private IMyView _view;26.  27. public IMyView View28. {

Page 9: Curso Linq

29. get30. {31. return _view;32. }33. }34.  35. public Presenter(IMyView view)36. {37. _view = view;38. }39. // business logic;40. }

La forma en que usamos las clases es esta:

1. SomeView view = new SomeView();2. Presenter presenter = new Presenter(view);3. presenter.View.BackgroundColor = "black";

Si en un momento determinado vamos a usar una clase que implementa IMyView pero que ademas añade algunas propiedades o funciones que no están en la interfaz, entonces necesitamos hacer typecast:

1. SpecialView view = (SpecialView) presenter.View;2. view.SpecialField = "whatever";

Puesto que presenter.View es del tipo IMyView, no podemos hilar más fino que eso, y desde que la jerarquía de clases crece empezamos a tener que hacer typecasts. La desventaja es la misma que en el caso anterior, que el error sólo aparece en tiempo de ejecución. La transformación a generics es sencilla:

1.  2. public class GPresenter<T>3. where T: IMyView4. {5. private T _view;6.  7. public T View8. {9. get10. {11. return _view;12. }13. }14.  15. public GPresenter(T view)16. {17. _view = view;18. }19. // business logic20. }21.  22. SomeView smView = new SomeView();

Page 10: Curso Linq

23. GPresenter<SomeView> gpresenter = new GPresenter<SomeView>(smView);24. gpresenter.View.BackgroundColor = "black";

Si en lugar de instanciar SomeView, instanciamos SpecialView, el autocompletado del IDE nos ofrecerá el campo SpecialField al teclear gpresenter.View.. Esto evita el error en tiempo de ejecución, lo cual es muy valioso. La clase GPresenter hace lo mismo que Presenter, pero su relación con las clases que implementan IMyView es fuértemente tipada, y eso le hace ganar en eficiencia y detección de errores.Forma de detectar el uso de generics: Estamos haciendo typecasts desde interfaces a clases concretas.

Métodos con Generics

Esto no es más que una extensión de lo anterior. Supongamos que la clase GPresenter tiene un método que realiza determinada operación y como resultado devuelve un objeto. Podemos saber que el objeto será de tipo IMyView, y escribir la firma del método así:

1. public IMyView SomeOperation()

Sin embargo, esto nos lleva denuevo al caso del typecast anterior. La solucion es la forma generica:

1. public T SomeOperation<T>()

Si este tipo es distinto del que usamos para View, podemos agregar otro tipo genérico a la definición de la clase:

1.  2. public class GPresenter<T, Y>3. where T: IMyView4. where Y: IMyOtherInterface5.  

Más que llamar a los parámetros genéricos, T e Y, conviene ponerles nombre, e.j, View y LoQueSea. La sintaxis de genérics no pone restricciones a los nombres que queramos poner a los parámetros.

Generics para envolturas (wrappers)

¿Cómo hacer genéricas clases cuyo código fuente no tenemos?. Como ejemplo os propongo el código fuente del GenericComboBox para WPF de DesktopRails. El control ComboBox de WPF tiene un campo Items que son los elementos que contiene el combo (dropdown o desplegable, como le querais llamar). Este campo es una lista de System.Object para que se pueda meter cualquier tipo de objeto y para que un combo pueda contener diferentes tipos de objeto. Sin embargo yo necesitaba saber que en determinadas ocasiones los elementos del combo eran todos del tipo string, o del tipo int para evitar errores en ejecución. La solución es crear una nueva clase que envuelve a la que nos interesa. Dentro de dicha clase

Page 11: Curso Linq

estamos obligados a hacer typecast en algún momento, con lo que aquí no ganamos en eficiencia, pero ganamos en detección de errores en tiempo de compilación.

1.  2. public class MyWrapper<T>3. {4. private TheClassWeWantToWrap _myWrap;5. // ...6. public List<T> Items7. {8. get9. {10. return (T)_myWrap.Items;11. }12. set13. {14. _myWrap.Items = value;15. }16. }17. }

Los Generics NO son polimórficos

Una cosa que hay que tener clara es que cuando se usa un tipo genérico, no se está heredando de él, simplemente se está diciendo al compilador que haga una seria de sustituciones en la plantilla. Dada la clase MyGenericBase:

1.  2. public class MyGenericBase<T>3.  

Las instancias:

1.  2. MyGenericBase<int> instanceY = ...;3. MyGenericBase<string> instanceX = ...;4.  

No son hijas de MyGenericBase, solo son sustituciones. Para que haya polimorfismo hay que extender al definiar la clase:

1.  2. public class PresenterChild<T> : GPresenter<T>3. where T: IMyView4.  

Por tanto en diseños de clases, normalmente la clase genérica base suele implementar una interfaz de modo que tanto su jerarquía como las instancias que usen esa plantilla pertenezcan a la familia de la interfaz:

1.  

Page 12: Curso Linq

2. public class MyGenericBase<T> : IMyHierarchy3.  

Véase como ejemplo más complejo el AbstractController de DesktopRails.

La declaración de los tipos genéricos NO es recursiva pero sí compleja

Algunas definiciones de clases genéricas son difíciles de leer, como le ocurre a BusinessBase del framework CSLA:

1.  2. public abstract class BusinessBase<T> : BusinessBase3. where T: BusinessBase<T>4.  

A primera vista parece una definición recursiva, imposible de interpretar. Sin embargo el compilador sólo hace la sustitución una vez y se usaría así:

1.  2. public class Customer: BusinessBase<Customer>3.  

BusinessBase es una template genérica que opera sobre un parámetro T. Así algunos métodos devuelven como resultado un objeto de tipo T. Al imponer en la cláusula "where" que el tipo T, debe ser sí mismo, lo que hacemos es eliminar el parámetro genérico en la clase que extiende de ella. Es decir, si B hereda de A, entonces B tambien es A, de ahí el truco. Esta es una definición rebuscada. El autor símplemente quería tener una clase sin parámetros genericos para que al usarla, en lugar de hacer:

1.  2. BusinessBase<Customer> customer = new BusinessBase<Customer>();

Pudiera directamente hacer:

1. Customer customer = new Customer();

Pero reusando toda la jerarquia de BussinesBase que casualmente usa parámetros genéricos. Esto es un truco que podemos recordar cuando queramos eliminar los parámetros genéricos de una clase que hereda de otra genérica.

Véamos otra clase que escribí para DesktopRails. Se trata de una relación como en el primer ejemplo de este artículo, en este caso entre Controller y View. Lo que pasa es que la relación es doble. Necesitaba que desde Controller pudiera haber una referencia a View, pero desde View quería que también hubiese una relación a Controller, porque se hacen llamadas en ambos sentidos.

1.  2. public interface IView<C> : IView3. where C : AbstractController

Page 13: Curso Linq

4. ...5. public abstract class AbstractController<V, C> : AbstractController6. where C : AbstractController<V,C>7. where V : IView<C>8.  

Modo de uso:

1.  2. public class UsersListController : AbstractController<IUsersListView, UsersListController>3. ...4. public interface IUsersListView : IView<UsersListController>5.  

En este caso, una instancia de UsersListController no conoce con precision de que tipo es su View(porque la clase tiene un campo View del tipo genérico IUsersListView), solo sabe que es de la jerarquia IUsersListView. Sin embargo, la instancia de una clase que implemente IUsersListView sí que sabe con precisión cual es el tipo exacto de Controller que tiene asociado, es una relación fuertemente tipada en esta dirección.Lo que estas cláusulas "where" aseguran es que cuando al controlador X, se le pase una vista Y, esa vista Y debe haber sido definida como vista que puede usar un controlador X.Así podemos descubrir errores como éste en tiempo de compilación:

1.  2. public interface IUsersListView: IView<ControllerX>3. ...4. public class UsersListController : AbstractController<IUsersListView, UsersListController>5.  

Lo anterior no compilaría. Es útil darse cuenta de que la asociación que se está haciendo es incorrecta, en tiempo de compilación y no que falle en tiempo de ejecución.Regla fácil:Cuando vemos una declaración que parece recursiva, donde la cláusula "where" del parámetro genérico es igual a la propia declaración, eso es como decir, sí mismo. La clase está diciendo, yo misma. Entonces el modo de uso es repitiendo el nombre:

public class UsersListController : AbstractController<IUsersListView, UsersListController>

A la hora de escribir una declaración como AbstractController, sabremos que debemos usar esta sintaxis de aspecto recursivo cuando queremos hacer referencia a la propia clase que estamos definiendo. Esto será cuando queramos hacer una referencia entre varios tipos genéricos y a uno de ellos se le dice que su relación con otro es el otro mismo.

Otro ejemplo menos complicado contenido en DesktopRails es el AbstractData:

1.  2. public abstract class AbstractData<TBaseView, C, TFinalView> : IUIData3.  4. where TBaseView : IView

Page 14: Curso Linq

5.  6. where C : AbstractController7.  8. where TFinalView : TBaseView9.  

En esta definición, se pasa el parámetro TBaseView sólo para forzar que es padre de TFinalView en la jerarquía. En verdad no se llega a usar TBaseView sino que sólo se usa para forzar una jerarquía. El sentido a esta relación se le ve cuando vemos clases derivadas:

1.  2. public abstract class AbstractUsersListData<T> : AbstractData<IUsersListView,

UsersListController, T>, IUsersListData3. where T : IUsersListView4. ...5. public class TestUsersListData : AbstractUsersListData<TestUsersListView>6.  

Al ver ésta última clase de la jerarquía puedes entender que estamos forzando a que TestUsersListView sea una vista que implementa IUsersListView.

La verdad es que cuando estas diseñando las clases, inicialmente a uno no se le ocurre escribir estas cláusulas a no se que tengas muuucha experiencia escribiendo clases iguales. Lo que suelo hacer, al menos yo que no tengo más materia gris que la media, es ir modificando las cláusulas según me va haciendo falta e ir dejando que el compilador me ayude a ver si todo va bien. Suelo pensar en términos de... "si alguien usa mi clase, quiero que la use de esta manera, y quiero que si la usa de tal otra forma el compilador le de un error y no le deje". Más bién diseño al revés. Pienso en cómo quiero usar la clase y la voy diseñando. Al estilo TDD.Existen más cláusulas "where" que se pueden especificar y que podeis leer en documentación. Por ejemplo si no sabes con exactitud la interfaz que quieres que implemente el tipo T pero sabes que quieres que sea una clase y no un tipo básico, puedes poner esto:

1. where T : class

Agradezco que las dudas o sugerencias sobre éste artículo se gestionen en forma de comentarios en el mismo, así como los errores que podais encontrar en él. Espero que os sea de utilidad.

Page 15: Curso Linq

Métodos genéricos en C#Los métodos genéricos son interesantes herramientas que están con nosotros desde los tiempos del .NET Framework 2.0 y pueden resultarnos muy útiles de cara a la construcción de frameworks o librerías reutilizables.

Podríamos considerar que un método genérico es a un método tradicional lo que una clase genérica a una tradicional; por tanto, se trata de un mecanismo de definición de métodos con tipos parametrizados, que nos ofrece la potencia del tipado fuerte en sus parámetros y devoluciones aun sin conocer los tipos concretos que utilizaremos al invocarlos.

Vamos a profundizar en el tema desarrollando un ejemplo, a través del cual podremos comprender por qué los métodos genéricos pueden sernos muy útiles para solucionar determinado tipo de problemas, y describiremos ciertos aspectos, como las restricciones o la inferencia, que nos ayudarán a sacarles mucho jugo.

Escenario de partidaComo sabemos, los métodos tradicionales trabajan con parámetros y retornos fuertemente tipados, es decir, en todo momento conocemos los tipos concretos de los argumentos que recibimos y de los valores que devolvemos. Por ejemplo, en el siguiente código, vemos que el método Maximo, cuya misión es obvia, recibe dos valores integer y retorna un valor del mismo tipo:

public int Maximo(int uno, int otro) { if (uno > otro) return uno; return otro; } Hasta ahí, todo correcto. Sin embargo, está claro que retornar el máximo de dos valores es una operación que podría ser aplicada a más tipos, prácticamente a todos los que pudieran ser comparados. Si quisiéramos generalizar este método y hacerlo accesible para otros tipos, se nos podrían ocurrir al menos dos formas de hacerlo.

La primera sería realizar un buen puñado de sobrecargas del método para intentar cubrir todos los casos que se nos puedan dar:

public int Maximo(int uno, int otro) { ... } public long Maximo(long uno, long otro) { ... } public string Maximo(string uno, string otro) { ... } public float Maximo(float uno, float otro) { ... } // Hasta que te aburras... Obviamente, sería un trabajo demasiado duro para nosotros, desarrolladores perezosos como somos. Además, según Murphy, por más sobrecargas que creáramos seguro que siempre nos faltaría al menos una: justo la que vamos a necesitar ;-).

Page 16: Curso Linq

Otra posibilidad sería intentar generalizar utilizando las propiedades de la herencia. Es decir, si asumimos que tanto los valores de entrada del método como su retorno son del tipo base object, aparentemente tendríamos el tema resuelto. Lamentablemente, al finalizar nuestra implementación nos daríamos cuenta de que no es posible hacer comparaciones entre dos object's, por lo que, o bien incluimos en el cuerpo del método código para comprobar que ambos sean comparables (consultando si implementan IComparable), o bien elevamos el listón de entrada a nuestro método, así:

public object Maximo(IComparable uno, object otro) { if (uno.CompareTo(otro) > 0) return uno; return otro; } Pero efectivamente, como ya habréis notado, esto tampoco sería una solución válida para nuestro caso. En primer lugar, el hecho de que ambos parámetros sean object o IComparable no asegura en ningún momento que sean del mismo tipo, por lo que podría invocar el método enviándole, por ejemplo, un string y un int, lo que provocaría un error en tiempo de ejecución. Y aunque es cierto que podríamos incluir código que comprobara que ambos tipos son compatibles, ¿no tendríais la sensación de estar llevando a tiempo de ejecución problemática de tipado que bien podría solucionarse en compilación?

El método genéricoFijaos que lo que andamos buscando es simplemente alguna forma de representar en el código una idea conceptualmente tan sencilla como: "mi método va a recibir dos objetos de un tipo cualquiera T, que implemente IComparable, y va a retornar el que sea mayor de ellos". En este momento es cuando los métodos genéricos acuden en nuestro auxilio, permitiendo definir ese concepto como sigue:

public T Maximo<T>(T uno, T otro) where T: IComparable { if (uno.CompareTo(otro) > 0) return uno; return otro; } En el código anterior, podemos distinguir el parámetro genérico T encerrado entre ángulos "<" y ">", justo después del nombre del método y antes de comenzar a describir los parámetros. Es la forma de indicar que Maximo es genérico y operará sobre un tipo cualquiera al que llamaremos T; lo de usar esta letra es pura convención, podríamos llamarlo de cualquier forma (por ejemplo MiTipo

Maximo<MiTipo>(MiTipo uno, MiTipo otro)), aunque ceñirse a las convenciones de codificación es normalmente una buena idea.

A continuación, podemos observar que los dos parámetros de entrada son del tipo T, así como el retorno de la función. Si no lo ves claro, sustituye mentalmente la letra T por int (por ejemplo) y seguro que mejora la cosa.

Page 17: Curso Linq

Lógicamente, estos métodos pueden presentar un número indeterminado de parámetros genéricos, como en el siguiente ejemplo:

public TResult MiMetodo<T1, T2, TResult>(T1 param1, T2 param2) { // ... cuerpo del método } 

Restricciones en parámetros genéricosRetomemos un momento el código de nuestro método genérico Maximo:

public T Maximo<T>(T uno, T otro) where T: IComparable { if (uno.CompareTo(otro) > 0) return uno; return otro; } Vamos a centrarnos ahora en la porción final de la firma del método anterior, donde encontramos el código where T: IComparable. Se trata de una restricción mediante la cual estamos indicando al compilador que el tipo T podrá ser cualquiera, siempre que implementente el interfaz IComparable, lo que nos permitirá realizar la comparación.

Existen varios tipos de restricciones que podemos utilizar para limitar los tipos permitidos para nuestros métodos parametrizables:

where T: struct, indica que el argumento debe ser un tipo valor. where T: class, indica que T debe ser un tipo referencia. where T: new(), fuerza a que el tipo T disponga de un constructor público sin parámetros; es

útil cuando desde dentro del método se pretende instanciar un objeto del mismo. where T: nombredeclase, indica que el argumento debe heredar o ser de dicho tipo. where T: nombredeinterfaz, el argumento deberá implementar el interfaz indicado. where T1: T2, indica que el argumento T1 debe ser igual o heredar del tipo, también

argumento del método, T2.

Un último detalle relativo a esto: a un mismo parámetro se pueden aplicar varias restricciones, en cuyo caso se separarán por comas, como aparece en el siguiente ejemplo: public TResult MiMetodo<T1, T2, TResult>(T1 param1, T2 param2) where TResult: IEnumerable where T1: new(), IComparable where T2: IComparable, ICloneable { // ... cuerpo del método } En cualquier caso, las restricciones no son obligatorias. De hecho, sólo debemos utilizarlas cuando necesitemos restringir los tipos permitidos como parámetros genéricos, como en el ejemplo del método Maximo<T>, donde es la única forma que tenemos de asegurarnos que las instancias que nos lleguen en los parámetros puedan ser comparables.

Page 18: Curso Linq

Uso de métodos genéricosA estas alturas ya sabemos, más o menos, cómo se define un método genérico, pero nos falta aún conocer cómo podemos consumirlos, es decir, invocarlos desde nuestras aplicaciones. Aunque puede intuirse, la llamada a los métodos genéricos debe incluir tanto la tradicional lista de parámetros del método como los tipos que lo concretan. Vemos unos ejemplos:

string mazinger = Maximo<string>("Mazinger", "Afrodita"); int i99 = Maximo<int>(2, 99); Una interesantísima característica de la invocación de estos métodos es la capacidad del compilador para inferir, en muchos casos, los tipos que debe utilizar como parámetros genéricos, evitándonos tener que indicarlos de forma expresa. El siguiente código, totalmente equivalente al anterior, aprovecha esta característica:

string mazinger = Maximo("Mazinger", "Afrodita"); int i99 = Maximo(2, 99); El compilador deduce el tipo del método genérico a partir de los que estamos utilizando en la lista de parámetros. Por ejemplo, en el primer caso, dado que los dos parámetros son string, puede llegar a la conclusión de que el método tiene una signatura equivalente a string Maximo(string, string), que coincide con la definición del genérico.

Otro ejemplo de método genéricoVeamos un ejemplo un poco más complejo. El método CreaLista, aplicable a cualquier clase, retorna una lista genérica (List<T>) del tipo parametrizado del método, que rellena inicialmente con los argumentos (variables) que se le suministra:

public List<T> CreaLista<T>(params T[] pars) { List<T> list = new List<T>(); foreach (T elem in pars) { list.Add(elem); } return list; }

// ... // Uso: List<int> nums = CreaLista<int>(1, 2, 3, 4, 6, 7); List<string> noms = CreaLista<string>("Pepe", "Juan", "Luis");  Otros ejemplos de uso, ahora beneficiándonos de la inferencia de tipos:

List<int> nums = CreaLista(1, 2, 3, 4, 6, 7); List<string> noms = CreaLista("Pepe", "Juan", "Luis");

// Incluso con tipos anónimos de C# 3.0: var p = CreaLista( new { X = 1, Y = 2 }, new { X = 3, Y = 4 }

Page 19: Curso Linq

); Console.WriteLine(p[1].Y); // Pinta "4" En resumen, se trata de una característica de la plataforma .NET, reflejada en lenguajes como C# y VB.Net, que está siendo ampliamiente utilizada en las últimas incorporaciones al framework, y a la que hay que habituarse para poder trabajar eficientemente con ellas.

Page 20: Curso Linq

Inferencia de Tipos: ¿Cómo funciona?

Si hay algo que veo que cuesta que los desarrolladores entiendan o mejor dicho confíen es en la inferencia de tipos que presenta .net Framework 3.5. Muchos creen que al usar la palabra var, están  resucitando al costoso tipo Variant de Visual Basic 6.0 o creen que están declarando una variable del tipo Object y que en tiempo de ejecución se resuelve el tipo al que pertenece dicha variable como los hacen los lenguajes dinámicos.

Afortunadamente no es así, la resolución del tipo al que pertenece una variable se resuelve en tiempo de compilación no en tiempo de ejecución. Vamos a verlo con un ejemplo:

La inferencia de tipos es un proceso por el cual el compilador determina el tipo de una variable local que ha sido declarada sin una declaración explícita de su tipo. El tipo es inferido a partir del valor inicial provisto a la variable. A continuación he declarado una variable llamada “inferredType”, cuyo tipo será resuelto por el compilador C# teniendo en cuenta por supuesto el contenido de la variable. Lo cual revela que para que el algoritmo de inferencia de tipos funcione es necesaria una entrada, que es el contenido de la variable. Si no inicializamos la variable a inferir  tendremos un error de compilación.

La ejecución nos revela que el compilador ha inferido que el contenido de “inferredType” es del tipo System.Int32.

Este resultado sería el mismo que obtendríamos si hubiéramos escrito el siguiente código:

Page 21: Curso Linq

La mejor forma de verificar esto es analizando el IL que generan ambas implementaciones tanto la inferida como la explícita. Con la ayuda de Reflector el código fuente en C# que se obtiene de analizar el IL de ambos ejecutables es exactamente el mismo.

Ahora bien, analicemos esta situación de error:

Page 22: Curso Linq

Particularmente lo que sucede en este caso, es que el compilador ya infirió que el tipo de la variable “inferredType” es System.Int32. Al asignarle contenido de tipo System.String tenemos un error de conversión de tipos. Me parece importante destacar esta situación ya que conozco a mucha gente que pretende que el compilador analice todas las posibles expresiones en las que interviene la variable y posteriormente generalice al tipo más adecuado para la misma. Pues les tengo malas noticias, el algoritmo de inferencia funciona a partir de la primera evaluación eventual   de una expresión, y esto está bien que sea así ya que la función del compilador es resolver el tipo mediante la reducción de expresiones al tipo atómico más implícito que le permita compilar. En el caso de este ejemplo la expresión analizar es una constante numérica. Si se analizaran todas las expresiones en las que interviene una variable para posteriormente generalizar al mejor tipo, el compilador necesitaría  una instancia privada de SQL Server Analisys Services y tardaría bastante tiempo en generar un ejecutable, lo cual no es la idea.Ahora si queremos ver el mismo ejemplo con una cadena de texto , el código es el siguiente:

Page 23: Curso Linq

Al ejecutarlo obtenemos:

Y cuando analizamos el IL con reflector, conseguimos:

La inferencia en los tipos por valor generaliza al tipo más implícito y optimizado del .net Framework. Como el Framework optimiza la performance para tipos enteros de 32-bit(System.Int32 y System.UInt32) un valor de 0,10 ó 100 que perfectamente podría inferirse como System.Byte se infiere como System.Int32. Incluso se recomienda usar los tipos enteros para contadores (aunque contemos de 0 a 10) y variables enteras de acceso frecuentes, ya que la performance en tiempo de ejecución del tipo entero es preferible al storage en RAM que ahorramos si declaramos variables como System.SByte, System.Byte y System.Int16. De la misma manera, con valores de  punto flotante si declaramos una variable con un valor de 3.14 será inferida al tipo System.Double y no como System.Single(float) que perfectamente la puede contener. La razón es que las operaciones con System.Double son optimizadas por hardware. Sólo se infiere a un tipo no optimizado por el Framework (como System.Int64 ó System.Decimal) si el valor de la variable está fuera del rango de los tipos optimizados.

Page 24: Curso Linq

Si por ejemplo queremos que se infiera el valor 3.14 como float en vez de double, debemos proporcionar cierta evidencia que ayude al compilador a inferirlo como float.

var inferredType= (float)3.14; // casting explícito

var inferredType = 3.14f; // notación sufijo

Entonces, resumiento:

La inferencia de tipos no es una solución automágica, el compilador no es psíquico ni el tipo de la variable se resuelve utilizando mecanismos de código dinámico, que afecten la performance en tiempo de ejecución.

La inferencia de tipos se resuelve en tiempo de compilación, por lo tanto existe un costo en tiempo de compilación, ese costo es el tiempo que tarda el algoritmo de inferencia en sintetizar una expresión y resolver el tipo de una variable. 

La inferencia de tipos tanto de valor como de referencia es para variables locales de métodos. No se aplica para variables de clase, propiedades, parámetros ni valores de retorno.

La inferencia de tipos no es nada más que azúcar sintáctica. Es decir una forma de endulzar y agilizar la manera de declarar variables locales. Realmente se aprecia y se valora  cuando se usa para el desarrollo de pruebas unitarias.

El tipo generado por el proceso de inferencia NO es un VARIANT. Visual Basic  6.0 ha sido discontinuado y es considerado tecnología legacy así que actualícense a Visual Basic.net

Page 25: Curso Linq

Tipos anónimos en C#.NET¿Que es?

Antes de nada, tipos anónimos no es lo mismo que inferencia de datos.

Los tipos anónimos difieren de la inferencia de datos. La inferencia se usa para crear tipos de objetos ya existentes, y los tipos anónimos, para crear objetos “recortados”, los creas “al vuelo”.

Me explico, lo que puedes crear con los tipos anónimos son objetos, de los cuales solo puedes puedes definir las propiedades.

var persona = new { nombre="Eric", apellido="Torre", diaNacimiento=9};

Vamos a ello

Con el anterior código, hemos creado un objeto con las propiedades de nombre(String), apellido(String),diaNacimiento(Integer). Lo que hace internamente es lo siguiente:

El objeto se declararía así (internamente):

class f__AnonymousType0<T0, T1, T2>{public T0 nombre;public T1 apellido;public T2 diaNacimiento;}

Y la declaración sería (internamente):

var persona = new f__AnonymousType0<string, string, int>{"Eric", "Torre", 9};

Para comparar los objetos anónimos, comprobara el contenido de las propiedades, se puede usar Equals o == , la diferencia es que Equals comprueba también el tipo.

Anónimos con Arrays

Por supuesto, una propiedad puede interesarnos que una propiedad sea un array, este ejemplo son de un listado de lenguajes de programación y otro parámetro, que es el día de nacimiento:

var persona = new{nombre="for",apellido="Code",lenguajes= new[]{

Page 26: Curso Linq

new {nombre="Php"},new {nombre=".Net"},new {nombre="java"}},diaNacimiento=9};

Anónimos con colecciones

Por supuesto, una propiedad puede interesarnos que una propiedad sea una colección, este ejemplo son de un listado de lenguajes de programación:

var persona = new{ nombre="Eric", apellido="Torre", lenguajes= (new[]{ new {nombre="php"}, new {nombre="vb"}, new {nombre="c#"}, new {nombre="asp"}, new {nombre="java"} })ToList(), diaNacimiento=9};

Esperamos que os sirva de ayuda!

Page 27: Curso Linq

Inicializadores de objeto y de colección

Los inicializadores de objeto permiten asignar valores a los campos o propiedades accesibles de un objeto en el momento de la creación sin tener que invocar explícitamente un constructor. En el ejemplo siguiente se muestra cómo utilizar un inicializador de objeto con un tipo con nombre, Cat. Tenga en cuenta el uso de propiedades auto implementadas en la clase Cat. Para obtener más información, vea Propiedades autoimplementadas (Guía de programación de C#).

C#

class Cat{ // Auto-implemented properties. public int Age { get; set; } public string Name { get; set; }}

C#

Cat cat = new Cat { Age = 10, Name = "Fluffy" };

Inicializadores de objeto con tipos anónimos

Aunque los inicializadores de objeto se pueden utilizar en cualquier contexto, son especialmente útiles en expresiones de consulta LINQ. Las expresiones de consulta utilizan con frecuencia los tipos anónimos, que solo se pueden inicializar con un inicializador de objeto, como se muestra en la siguiente declaración.

var pet = new { Age = 10, Name = "Fluffy" };

Los tipos anónimos habilitan la cláusula select de una expresión de consulta de LINQ para transformar objetos de la secuencia original en objetos cuyo valor y forma pueden ser distintos de los originales. Esto es muy útil si solo desea almacenar una parte de la información de cada objeto de una secuencia. En el ejemplo siguiente se supone que un objeto de producto (p) contiene muchos campos y métodos, y el usuario sólo está interesado en crear una secuencia de objetos que contenga el nombre del producto y el precio por unidad.

C#

var productInfos = from p in products

Page 28: Curso Linq

select new { p.ProductName, p.UnitPrice };

Al ejecutar esta consulta, la variable productInfos contendrá una secuencia de objetos a la que se puede tener acceso en una instrucción foreach, como se muestra en este ejemplo:

foreach(var p in productInfos){...}

Cada objeto del nuevo tipo anónimo tiene dos propiedades públicas que reciben los mismos nombres que las propiedades o campos del objeto original. También puede cambiar el nombre de un campo al crear un tipo anónimo; en el ejemplo siguiente se cambia el nombre del campo UnitPrice a Price.

select new {p.ProductName, Price = p.UnitPrice};

Inicializadores de objeto con tipos que aceptan valores NULL

Es un error en tiempo de compilación para utilizar un inicializador de objeto con un struct que acepta valores NULL.

Inicializadores de colección

Los inicializadores de colección permiten especificar uno o más inicializadores de elemento cuando se inicializa una clase de colección que implementa IEnumerable. Los inicializadores de elemento pueden ser un valor simple, una expresión o un inicializador de objeto. Si se utiliza un inicializador de colección, no es necesario especificar varias llamadas al método Add de la clase en el código fuente; el compilador agrega las llamadas.

En los ejemplos siguientes se muestran dos inicializadores de colección simples:

List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };List<int> digits2 = new List<int> { 0 + 1, 12 % 3, MakeInt() };

El inicializador de colección siguiente utiliza inicializadores de objeto para inicializar los objetos de la clase Cat, que se define en un ejemplo anterior. Observe que los inicializadores de objeto individuales aparecen entre corchetes y separados por comas.

C#

List<Cat> cats = new List<Cat>{ new Cat(){ Name = "Sylvester", Age=8 },

Page 29: Curso Linq

new Cat(){ Name = "Whiskers", Age=2 }, new Cat(){ Name = "Sasha", Age=14 }};

Puede especificar null como elemento de un inicializador de colección si el método Add de la colección lo permite.

C#

List<Cat> moreCats = new List<Cat>{ new Cat(){ Name = "Furrytail", Age=5 }, new Cat(){ Name = "Peaches", Age=4 }, null};

Ejemplo

C#

// The following code consolidates examples from the topic.class ObjInitializers{ class Cat { // Auto-implemented properties. public int Age { get; set; } public string Name { get; set; } }

static void Main() { Cat cat = new Cat { Age = 10, Name = "Fluffy" };

List<Cat> cats = new List<Cat> { new Cat(){ Name = "Sylvester", Age=8 }, new Cat(){ Name = "Whiskers", Age=2 }, new Cat(){ Name = "Sasha", Age=14 } };

List<Cat> moreCats = new List<Cat> { new Cat(){ Name = "Furrytail", Age=5 }, new Cat(){ Name = "Peaches", Age=4 }, null };

Page 30: Curso Linq

// Display results. System.Console.WriteLine(cat.Name);

foreach (Cat c in cats) System.Console.WriteLine(c.Name);

foreach (Cat c in moreCats) if (c != null) System.Console.WriteLine(c.Name); else System.Console.WriteLine("List element has null value."); } // Output: //Fluffy //Sylvester //Whiskers //Sasha //Furrytail //Peaches //List element has null value.}

Page 31: Curso Linq

Métodos de extensión en C#

“Los métodos de extensión permiten “agregar” métodos a los tipos existentes sin necesidad de crear un nuevo tipo derivado y volver a compilar o sin necesidad de modificar el tipo original. Los métodos de extensión constituyen un tipo especial de método estático, pero se les llama como si se tratasen de métodos de instancia en el tipo extendido. En el caso del código de cliente escrito en C# y Visual Basic, no existe ninguna diferencia aparente entre llamar a un método de extensión y llamar a los métodos realmente definidos en un tipo.” MSDN

Ciertamente esta es una descripción bastante criptica de esta técnica de desarrollo que se puede utilizar para una mayor productividad y legibilidad de nuestro código. Por ello quiero escribir un artículo que, por medio de un ejemplo muy sencillo, pueda ser un paso inicial en el conocimiento de esta herramienta de programación.

Básicamente, y para entendernos de una forma más sencilla. Un método extensor es una forma de “añadirle“ métodos a una clase sin necesidad de hacerlo en la original o en alguna instancia/copia de la misma. No es un reemplazo de la técnica formal por medio de herencia, si no una pequeña “trampa” que nos permite obtener un resultado muy similar.

Preparando el proyecto

Page 32: Curso Linq

Actualmente estoy utilizando como editor principal el Visual Studio 11 Beta, que no cuesta ni un real (pero lo costará). Pero si quisiera un producto gratuito para programar en C# podría también utilizar el Visual Studio Express 11.

Para este artículo me creo un nuevo proyecto Web, de tipo MVC4 (que también es beta) vacío. He elegido este tipo para no tener ningún tipo de ruido en el ejemplo que quiero compartir. Por ello me voy a saltar la regla de hacer siempre test unitarios, y no voy a construir el proyecto de testing.

A continuación añado una página de clases en la carpeta de Modelo, llamada Comprobaciones, en donde voy a insertar una clase que realice diversas comprobaciones básicas y en donde voy a definir métodos extensores que me haga el código más legible.

El primer paso de mi ejemplo es enunciarlo. Describir la visión de lo que quiero hacer. Y esto es realizar una clase que me compruebe si los datos de un objeto Persona son correctos. La Persona va a tener dos propiedades: el nombre y la edad en años. Y por ello lo primero que voy a hacer es construir la estructura del objeto.

public class Persona { public string Nombre { get; set; } public int Edad { get; set; } }

Ahora continuo creando una clase de comprobaciones en donde generaré el método de entrada que se llamará esCorrecto, recibiendo como parámetro un objeto del tipo Persona. Como verás, la primera validación que debo realizar es que persona no sea un objeto nulo. Para ello hago algo tan simple como retornar si el objeto no es nulo.

public class Comprobaciones { public bool esCorrecto(Persona persona) { return persona != null; } }

Extendiendo a Persona

Pero mejoremos la legibilidad del código refactorizando con métodos extensores y creemos un nuevo método para la clase Persona. Esto se hace de forma muy sencilla creando una nueva clase estática llamada extensores en donde voy a dar de alta un método también estático que tiene la particularidad de extender la clase Persona de la siguiente forma.

Page 33: Curso Linq

public static class Extensores { public static Boolean IsNotNull(this Persona persona) { return persona != null; } }

Como ves en este ejemplo tan sencillo ganas un poquito de complejidad para ganar un poquito de legibilidad, quedando nuestro método de comprobaciones así.

public class Comprobaciones { public bool esCorrecto(Persona persona) { return persona.IsNotNull(); } }

Pero si lo piensas un poco, el saber si una clase es nula o no me puede venir muy bien en toda la aplicación en donde tendré muchos más objetos a los que hacer la misma comprobación. O sea que con muy poco esfuerzo puedo extender el propio tipo object y así TODOS mis objetos serán capaces de devolverme si son nulos o no. Incluyendo todas las clases, estructuras, enumeradores, etc. Ya que en C# todo hereda de object.

public static Boolean IsNotNull(this Object objeto) { return objeto != null; }

Así, con un solo método extensor puedo comprobar si la edad o el nombre son nulos de una forma, no solamente sencilla si no muy legible.

public class Comprobaciones { public bool esCorrecto(Persona persona) { return persona.Edad.IsNotNull(); } }

Page 34: Curso Linq

Pero vamos a darle una pequeña vuelta de tuerca extendiendo otra vez a la clase Persona para realizar la comprobación de que tiene un nombre válido. Como todos sabemos, en la última versión del framework de .NET podemos hacer dos comprobaciones diferenciadas que nos digan si la cadena de texto es nula, esta vacía o es un espacio en blanco. Por lo cual si quiero comprobar si el nombre es válido debo hacer dos llamadas diferenciadas.

public class Comprobaciones { public bool esCorrecto(Persona persona) { return string.IsNullOrEmpty(persona.Nombre) == false &amp;&amp; string.IsNullOrWhiteSpace(persona.Nombre); } }

Pero si utilizo un método extensor tal cual este,

public static Boolean NoTieneNombre(this Persona persona) { return string.IsNullOrEmpty(persona.Nombre) &amp;&amp; string.IsNullOrWhiteSpace(persona.Nombre); }

Voala, la legibilidad de mi código aumenta mucho y además tengo encapsulado en un solo sitio la lógica de comprobación del campo. Es más, así cumplo a rajatabla el concepto de que mi método no debe saber cómo se hacen las cosas, solamente esperar la respuesta adecuada; en este caso un valor booleano.

public class Comprobaciones { public bool esCorrecto(Persona persona) { return persona.NoTieneNombre(); } }

Conclusiones

Con esta técnica podemos obtener un código más legible y mantenible. Pero no es todo oro lo que reluce y hay que tener los inconvenientes inherentes a esta técnica.

Page 35: Curso Linq

Primero el código es dependiente del intellisense del Visual Studio, ya que desde el fichero fuente abierto no puedes saber si el método invocado es parte de la instancia o es un método extensor. Lo cual puede causar dolores de cabeza para localizar el código si no estás con el IDE adecuado.

Otro problema es que el ciclo de vida de la clase y de los métodos que la extiende pueden ser totalmente diferentes. Por lo cual un extensor que funcione bien en un momento, por un cambio en el objeto que extiende puede dejar de hacerlo correctamente.

Por último si se realiza un cambio en la clase extendida y se le añade un método de instancia con el mismo nombre que el método extensor, este dejará de funcionar ya que el compilador utilizará antes el método de instancia que el extensor. Lo cual es un error muy difícil de localizar.

A causa de ello, se aconseja darle prioridad al uso de los métodos de instancia y a la herencia, antes que a los métodos extensores. Lo cual no quita que herramientas como Linq esté construida en su totalidad con esta técnica de desarrollo.

Ahora solo queda, probar y practicar, para tener un conocimiento en más profundidad que te permita tomar las decisiones más productivas.

namespace GenbetaDevMVC4.Models

{ public class Persona { public string Nombre { get; set; } public int Edad { get; set; } }

public class Comprobaciones { public bool esCorrecto(Persona persona) { return ! persona.NoTieneNombre(); } }

public static class Extensores { public static Boolean IsNotNull(this Object objeto) { return objeto != null; } public static Boolean NoTieneNombre(this Persona persona) { return string.IsNullOrEmpty(persona.Nombre) && string.IsNullOrWhiteSpace(persona.Nombre);

Page 36: Curso Linq

} }}

03/05/2012 He añadido un enlace a una biblioteca de métodos extensores que será de gran utilidad.

Page 37: Curso Linq

Delegados en C#

Introducción

Uno de los temas que más suelen confundir a los nuevos programadores de la plataforma .NET, al menos a mí, son los delegados. Para los programadores de C++ el concepto es muy similar al de los punteros a funciones, los programadores de JavaScript tienen una funcionalidad parecida a través de objetos Function (que rara vez se utilizan), pero para el resto es totalmente nuevo.

Lo primero que vamos a hacer es intentar definir que son los delegados. Una buena definición seria: 

Los delegados son un tipo que representa a una función con una determinada declaración.

Vamos a analizar esta definición poco a poco, ya que dice mucho en muy pocas palabras...

Los delegados son un TIPO. Los delegados representan a una función. La función debe tener una determinada declaración.

Si un delegado es un tipo, entonces puedo crear variables de ese tipo. También hemos dicho que un delegado representa a una función, por lo que una variable creada de un tipo delegado es la representación de una determinada función. Por úlitmo hemos dicho que esta función debe tener una determinada declaración.

Un ejemplo sencillo.

Veamos un ejemplo que es como mejor se ven las cosas:

using System;namespace Devjoker.Ejemplos {   delegate int myDelegate(int arg) ;}

En este caso hemos declarado un tipo delegado, al que hemos llamado myDelegate que representa a una función que devuelve un entero y que recibe como argumento también un entero. Como es un tipo no es necesario definirlo dentro de una clase. Como resultado vamos a poder declarar variables del tipo myDelegate.

La siguiente pregunta seria: ¿Como declaro variables de tipo myDelegate? ¿Y como asigno "valores" a esa variable? Los delegados se declaran como cualquier otro objeto en .NET, recordemos que todo en .NET son objetos y los delegados no son una excepción. Para

Page 38: Curso Linq

asignar un delegado, no debemos asignar un "valor", sino un método, normalmente una funcion. El método al que asignemos el delegado no puede ser una función cualquiera, debe cumplir con la declaración del delegado. La forma de asignarlo es a través del constructor del delegado, pasando como argumento la función.

A continuacion mostramos dos posibles funciones que cumplen con la declaración del delegado:

private int delegateFunction1(int a){      Console.WriteLine("Ejecutando ... delegateFuntion1");      return ++a;}private int delegateFunction2(int a){      Console.WriteLine("Ejecutando ... delegateFuntion2");      return a;}

Como podemos ver tanto delegateFuntion1 como delegateFunction2 son functiones que devuelven un tipo int y reciben como parametro un int, que es la forma en la que hemos declarado el delegado.

La declaración de una variable con el tipo delegado, es la siguiente, como cualquier otra variable en C#:

myDelegate variableDelegado;

Ahora vamos a ver como asignar un delegado. Hemos dicho que para asignar un delegado necesitamos utilizar el constructor del mismo. En el siguiente ejemplo vamos a ver un pequeño programa completo que declara y ejecuta un delegado:

using System;namespace Devjoker.Ejemplos {   delegate int myDelegate(int arg) ;      class MainClass   {       public static void Main(string[] args)      {             MainClass instancia = new MainClass();                        myDelegate variableDelegado;            variableDelegado =             new myDelegate(instancia.delegateFunction1);            int a = variableDelegado(5);            System.Console.WriteLine("El resultado obtenido es ... {0}",a);      }

Page 39: Curso Linq

            private int delegateFunction1(int a)      {            Console.WriteLine("Ejecutando ... delegateFuntion1");            return ++a;      }

      private int delegateFunction2(int a)      {            Console.WriteLine("Ejecutando ... delegateFuntion2");            return a;      }   }}

En este ejemplo declaramos una variable variableDelegado y la asignamos a la función delegateFunction1. Debido a que el método Main es estático, pero delegateFunction1 no lo es, necesitamos una instancia de la clase MainClass para referiros a la función de forma concreta. Por úlitmo ejecutamos nuestra variable (con un parámetro fijo 5) y mostramos el resultado en pantalla.  

El programa genera una salida similar a la siguiente:

Ejecutando ... delegateFuntion1El resultado obtenido es ... 6Presione una tecla para continuar . . .

Seguro que alguno de vosotros está pensando en que esto mismo podría hacerse invocando a la funcion sin más, y no andar con tanto lío. Por supesto, pero este es un ejemplo muy sencillo y no pretende mostrar los casos complicados, recordemos que queremos aprender que son y para que sirven los delegados.

Un caso más complejo podría ser el siguiente: Imaginemos un control creado dinamicamente por el programa, sobre el que queramos programar su click ... La forma de hacerlo es con delegados.

La función a la que asignamos el delegado no debe pertenecer a una clase en concreto, ni siquiera a un assemblie en particular, solo debe cumplir la declaración del delegado.

Vamos ahora a ver un ejemplo algo más práctico.

Un ejemplo practico.

El siguiente ejemplo, sin pretender entrar en mucha complejidad, es un sencillo programa que realiza su log de proceso bien por pantalla o en un fichero.

Page 40: Curso Linq

El programa tiene tres clases:

MainClass, que es la clase que contiene el método main. ProgramClass, que es la clase que contiene el programa principal. FormasLog, que es la clase que contiene las diferentes formas para realizar el log del

proceso.

El programa tiene además un delegado, que vamos a utilizar para realizar el log del proceso. Tiene la siguiente forma:

delegate void logDelegate(string arg);

Veamos cada una de estas clases. Empezaremos con la clase FormasLog, que tiene dos métodos (que coinciden con la declaración del delegado), ConsoleLog y FileLog. ConsoleLog muestra un mensaje en pantalla y FileLog, escribe el mensaje en un fichero (ubicado en la misma ruta que el assemblie).

El código de la clase es el siguiente:

class FormasLog      {            private static StreamWriter fw;            public static void ConsoleLog(string texto)            {                  System.Console.WriteLine(texto);            }            public static void FileLog(string texto)            {                  try                  {                        bool append = true;                        if (fw == null)                        {                              append = false;                        }                        fw = new StreamWriter( "ficherolog.log",append);                        fw.WriteLine(texto);                        fw.Close();                  }                  catch (IOException e)                  {                                               FormasLog.ConsoleLog(e.Message);                  }            }      }

La clase ProgramClass tiene los siguientes métodos y miembros:

Page 41: Curso Linq

logFunction, que es un miembro de tipo logDelegate y es la función encargada de realizar el log

Run, que es el método principal de la clase, unicamente comprueba que logFunction está asignada e itera 100 veces llamando al método Log.

SetLogMethod, este método es el más importante de todos, ya que recibe un parámetro de tipo logDelegate y lo asigna a logFunction para que pueda hacer su trabajo de forma correcta.

Log, este método ejecuta logFunction.

El código completo de la clase se muestra a continuacion:

Class ProgramClass      {            logDelegate logFunction;            public void Run()            {                  if (logFunction == null)                  {                  logFunction = new logDelegate(FormasLog.ConsoleLog);                  }                  int i = 0;                  do                  {                  logFunction("Este es el log! en la iteracion " + i.ToString());                  }                  while (i++<100);            }            public void SetLogMethod(logDelegate metodo)            {                  logFunction = metodo;            }                       private void Log(string texto)            {                  logFunction(texto);            }      }

Por último tenemos la clase MainClass que es la clase que contiene el método Main en el que se inicia la ejecución del programa.

El método Main crea una instancia de la clase ProgramClass a la que llamamos "programa", y solicita al usuario que especifique una forma para realizar el log. Dependiendo de la selección del usuario llama al método SetLogMethod del objeto "programa" pasandole una nueva variable de tipo logDelegate construida con las funciones que proporciona la clase FormasLog.

El código de la clase es:

Page 42: Curso Linq

Class MainClass      {            public static void Main(string[] args)            {                                   ProgramClass programa = new ProgramClass ();                  string valor = "";                  do                  {                  Console.WriteLine("?Que forma de log quiere?");                  Console.WriteLine("1->Consola 2->Fichero");                  valor = System.Console.ReadLine();                  }                  while (valor != "1" && valor!= "2" );                                                                      if (valor == "1")                  {                        programa.SetLogMethod(new logDelegate(FormasLog.ConsoleLog));                  }                  else if (valor =="2")                  {                        programa.SetLogMethod(new logDelegate(FormasLog.FileLog));                  }                  programa.Run ( );            }                               }

La gran ventaja de esta forma de trabajar es que podemos cambiar la forma en la que el programa realiza el log desde el exterior del programa sin ningún tipo de esfuerzo. Imaginemos que la clase FormasLog  y ProgramClass constituyen un componente de software compilado en un assemblie miComponente.dll. Por otro lado, la clase MainClass pertenece a otro assemblie completamente diferente, otroAssemblie.dll. En este escenario es posible que las formas de log que hemos predeterminado no sean suficientes como para cubrir las necesidades del programa, por ejemplo el log debe guardarse en una base de datos. Podríamos escribir una nueva funcion y decirle al componente que la utilice, solo tendríamos que llamar al metodo SetLogMethod.

El código completo del programa se muestra a continuación:

namespace Devjoker.Ejemplos {      delegate void logDelegate(string arg) ;            class MainClass      {            public static void Main(string[] args)            {                                   ProgramClass programa = new ProgramClass ();                  string valor = "";                  do

Page 43: Curso Linq

                  {                  Console.WriteLine("¿Que forma de log quiere?");                  Console.WriteLine("1->Consola 2->Fichero");                  valor = System.Console.ReadLine();                  }                  while (valor != "1" && valor!= "2" );                  if (valor == "1")                  {                        programa.SetLogMethod(new logDelegate(FormasLog.ConsoleLog));                  }                  else if (valor =="2")                  {                        programa.SetLogMethod(new logDelegate(FormasLog.FileLog ));                  }                  programa.Run ( );            }      }      class ProgramClass      {            logDelegate logFunction;            public void Run()            {                  if (logFunction == null)                  {                  logFunction = new logDelegate(FormasLog.ConsoleLog);                  }                                    int i = 0;                  do                  {                  logFunction("Este es el log! en la iteracion " + i.ToString());                  }                  while (i++<100);            }            public void SetLogMethod(logDelegate metodo)            {                  logFunction = metodo;            }            private void Log(string texto)            {                  logFunction(texto);            }                              }      class FormasLog      {            private static StreamWriter fw;            public static void ConsoleLog(string texto)            {                  System.Console.WriteLine(texto);            }            public static void FileLog(string texto)

Page 44: Curso Linq

            {                  try                  {                        bool append = true;                        if (fw == null)                        {                              append = false;                        }                        fw = new StreamWriter( "ficherolog.log",append);                        fw.WriteLine(texto);                        fw.Close();                  }                  catch (IOException e)                  {                                               FormasLog.ConsoleLog(e.Message);                  }            }      } }

Como hemos podido ver los delegados son una potentisima herramienta que ofrece, no solo C# sino la plataforma .NET.

Espero que este articulo os haya servido de ayuda para entender un poco mejor los delegados, y si teneis alguna duda al respecto no dudeis en exponerla en los foros.

Page 45: Curso Linq

Métodos anónimosEstoy seguro que usted recordará su primera clase de programación donde le enseñaron la manera de crear métodos e invocarlos. Pues bien, estos métodos que usted aprendió tienen una sintaxis que hacen prosible la invocación como la especificación de ciertos parámetros para este. Por ejemplo:

Public void miMetodo(int nro) { Console.Write("’{0}’ ", (char)nro); Console.Write("0x{0:X} ", nro); Console.Write("{0} ", nro);}

Hasta ahora todo es muy conocido. Hemos creado un método llamado miMetodo seguido de un parámetro  entero para este. La manera de invocarlo usando un delegado es muy fácil, y eso lo sabe usted bien. Bueno, así como existe este método con nombre, también existe los recien conocidos Métodos Anónimos, que viene con C# 2.0 como parte de una de sus novedades de programación. Pues usted se preguntará ¿y que és un método anónimo?  Un método anónimo es justamente eso, aquel método que no tiene un nombre específico. Y ahora usted se preguntará ¿y cómo invoco los método anónimos?, pues buena pregunta, la respuesta es usando Delegados.

El detalle es que siempre hemos estado acostumbrados a nombrar las métodos, tanto aquellos que devuelven valores nulos o los que devuelven un cierto valor para su posterior uso, y esta novedad de Métodos anónimos en C# 2.0, viene a ser el tema de este post. Es por eso que paso a explicar lo concerniente a Métodos Anónimos usando Delegados.

Lo importante es que los métodos anónimos,  reduce la sobrecarga de codificación al crear instancias de delegados sin tener que crear un método independiente. Un método anónimo es declarado con la palabra clave delegate seguido de una lista de parámetros. Las líneas de código para el método están dentro del par de llaves {}. Todo esto debe ser referenciado por un tipo delegate que tenga la misma firma que el método anónimo, es así que, la invocación de los métodos anónimos se realiza usando esta referencia. Vayamos con un ejemplo:

Lo primero que se debe hacer  es declarar el delegado.

delegate void toString(Boolean b);

En esta función, debemos instanciar el delegado correspondiente e invocarlo.

Static void Main(string[] args){ //referenciamos un delegate de tipo arriba definido. toString ts;

//declaramos un método anónimo usando delegado. ts = delegate(Boolean b) { Console.WriteLine("\ntoString: {0}", b == true ? "Verdadero”: "Falso");};

Page 46: Curso Linq

ts(true); //invocación del método anónimo usando delegado.

}

De esta manera  explotaremos la nueva funcionalidad de los métodos anónimos. Para entender mejor aquí algunos ejemplos más. He aquí otra demostración. Ya sabéis lo que se hace primero:

delegate void printIntView(int valor);

Ahora se deben instanciar los delegados y los métodos anónimos. Esto es explicado dentro de las siguientes líneas de código.

static void Main(string[] args){ //creamos los delegados a partir de tipo definido printIntView printIntView entero, hexa, oChar, EHC,HC, EC;

//otros métodos anónimos entero=delegate(int nro) { System.Console.Write("’{0}’ ", (char)nro); }; hexa = delegate(int nro) { System.Console.Write("0x{0:X} ", nro); }; oChar = delegate(int nro) { System.Console.Write("{0} ", nro); };

Console.Write("\nentero: "); entero(128); Console.Write("\n hexa: "); hexa(128); Console.Write("\nChar: "); oChar(128);

EHC = entero + hexa + oChar; // callbacks Console.Write("\nEHC: "); EHC(128);//invocación HC= EHC - entero; Console.Write("\nHC: "); HC(128);//invocación

EC = EHC - hexa; Console.Write("\nEC: "); HC(128); //invocación

Console.ReadLine();}

Ya sabéis esto de los métodos anónimos, y espero que nuevamente este post sea de utilidad.

Page 47: Curso Linq

C#: Desmitificando las expresiones lambda (I)Entre las múltiples novedades aparecidas con C# 3.0 y VB.NET 9.0, las expresiones lambda son sin duda una de las que en principio pueden parecer más complejas, probablemente por su relación con conceptos no demasiado asimilables como los delegados, inferencia de tipado, métodos anónimos, o tipos genéricos, entre otros.

Sin embargo, esa aparente dificultad desaparece en cuanto se les presta un poco de atención, y una vez comprendidas aportan a los desarrolladores una potencia y agilidad difíciles de lograr con las herramientas disponibles hasta el momento. Sólo hay que ver su amplia utilización dentro del propio .NET framework, LINQ, y nuevas plataformas como ASP.NET MVC, para darse cuenta de su importancia. Y por si fuera poco, según cuentan los expertos, su uso "engancha".

A lo largo de esta serie de tres posts intentaré describir las expresiones lambda desde un punto de vista práctico, con la única pretensión de aportar algo de luz a los que todavía no han sucumbido a su poder. ;-)

El objetivo de este primer post es puramente introductorio, y trataré conceptos y nociones básicas para poder abordar los siguientes. En el segundo post de la serie trataremos las expresiones lambda como funciones anónimas, dejando para el tercero los misteriosos árboles de expresión.

Introducción a las lambda

Según la definición en la Referencia del lenguaje C# de MSDN:

"Una expresión lambda es una función anónima que puede contener expresiones e instrucciones y se puede utilizar para crear delegados o tipos de árboles de expresión"

En la Guía de programación de Visual Basic 9 encontramos otra definición, muy simple y pragmática:

"Una expresión lambda es una función sin nombre que calcula y devuelve un solo valor. Se pueden utilizar las expresiones lambda dondequiera que un tipo de delegado sea válido"

ScottGu también aportó su granito de arena para hacer el concepto más cercano a los desarrolladores; como siempre, al grano:

"Las Expresiones Lambda aportan una sintaxis más concisa y funcional para escribir métodos anónimos."[...]"La forma más sencilla para conceptualizar las expresiones lambda es pensar en ellas como formas de escribir métodos breves en una línea."

Page 48: Curso Linq

Partiendo de estas definiciones, y de otras muchas aportadas por Google ;-), está claro que las lambda son funciones, es decir, un conjunto de intrucciones capaces de retornar un valor partiendo de los parámetros que se les suministra, aunque en determinados casos es posible que no reciba ningún parámetro, o que realicen una acción sin retornar nada. Igual que una función tradicional, vaya. Y de hecho, en el cuerpo de una expresión lambda puede haber casi de todo : llamadas a otras funciones, expresiones, bucles, declaraciones de variables...

Sin embargo, a diferencia de los métodos o funciones habituales, las lambdas no necesitan de un identificador, puesto que se declaran in situ, justo en el momento en que van a asignarse a una variable o a utilizarse como parámetro de una función, pasando el destinatario de esta asignación a actuar como delegado, o puntero, hacia la misma, o a ser el contenedor del árbol de expresión que la representa. Ein? Chino, eh? No pasa nada, dentro de poco estudiaremos estos dos usos en profundidad, pero antes vamos a ver cómo se definen las expresiones lambda a nivel de código.

Forma de las expresiones lambda

Las expresiones lambda en C# se escriben según el patrón descrito a continuación, al que le siguen algunos ejemplos que lo ilustran e introducen algunas particularidades.

Forma general: parámetros => expresión, donde:- parámetros: lista de parámetros separados por comas- "=>“: separador.- expresión: implementación de las operaciones a realizar

num => num * 2 // Lambda con un parámetro que retorna // el doble del valor que se le pasa.

(a, b) => a + b // Lambda con dos parámetros que retorna // la suma de ambos.

num => { // Lambda con cuerpo que recibe un int x = new Random().Next(); // entero, y retorna la suma de éste return num+x; // con un número aleatorio.}

() => DateTime.Now // Lambda que no recibe parámetros // y retorna la fecha y hora del sistema.

msg => Console.WriteLine(msg); // Recibe un parámetro, realiza una // acción y no retorna nada. Como se puede observar, cuando sólo existe un parámetro no es necesario utilizar paréntesis en el lado izquierdo de la expresión, mientras que hay que hacerlo en todos los demás casos. También es interesante destacar que las lambda con cuerpo deben utilizar return para retornar el valor deseado, cuando esto sea necesario.

Y un último dato: fijaos que ni los parámetros ni el retorno de la función tienen indicado un tipo. Aunque puede hacerse, normalmente no será necesario puesto que el compilador podrá inferir

Page 49: Curso Linq

(deducir) el tipo a partir de su contexto, más adelante veremos cómo es esto posible. Por tanto, no es necesario escribir código tan extenso como:

(int a, int b) => (int)(a+b) Y hasta aquí este primer post introductorio. En el siguiente trataremos de explicar el papel de las expresiones lambda como funciones anónimas y facilitadoras del trabajo con delegados.

Page 50: Curso Linq

C#: Desmitificando las expresiones lambda (II)En el post anterior intentamos realizar una primera aproximación a las expresiones lambda, centrándonos en obtener una definición lo suficientemente cercana, que nos permitiera conocer a grandes rasgos qué son, así como en describir su forma general y sus particularidades sintácticas.

En esta segunda entrega vamos a profundizar un poco en el papel de las expresiones lambda como vía para definir muy rápidamente funciones anónimas y los tipos de delegados con los que podemos referenciarlas, y por tanto, invocarlas.

Ya en el tercer post describiremos el papel de las expresiones lambda como herramienta de generación de árboles de expresión.

Las lambdas como funciones anónimasComo habíamos insinuado anteriormente, uno de los usos de las expresiones lambda es permitir la definición "en línea" de funciones anónimas. De hecho, en tiempo de compilación las expresiones lambda son convertidas en métodos a los que el compilador establece un nombre único autogenerado, como los ejemplos mostrados a continuación:

Las referencias a estas funciones anónimas son transformadas en delegados (punteros) a las mismas, lo que nos permitirá, por ejemplo, invocarlas desde el código. En la práctica esto quiere decir que podemos asignar una lambda a una variable y ejecutarla como muestra el siguiente pseudocódigo:

delegado duplica = x => x * 2; escribe duplica(2); // Escribe un 4 En este primer acercamiento, fijaos que duplica es el nombre del delegado, la función definida en forma de expresión lambda no tiene nombre, será el compilador el que se asigne uno.

Veamos cómo se concreta esta idea en C#. En el siguiente código, la variable duplica apunta hacia

Page 51: Curso Linq

una función anónima definida a través de la expresión lambda en cuya implementación lo único que se hace es retornar el doble del valor que le llega como parámetro. Vemos también cómo podemos utilizarla de forma directa:

Func<int, int> duplica = x => x * 2;int result = duplica(7); // result vale 14 Sólo con objeto de que podáis entender el código anterior, os adelantaré que la porción Func<int,

int> es una forma rápida de tipificar el delegado , indicando que duplica apunta a una función que espera un entero como parámetro de entrada, y que su valor de retorno será otro entero. Esto lo veremos dentro de un momento.

De la misma forma que asignamos la expresión lambda a una variable, podemos hacerlo también para indicar el valor de un parámetro a un método que acepte un delegado concreto. Por ejemplo, el siguiente código muestra un método llamado calcula que recibe un valor entero y una referencia a una función, retornando el resultado de efectuar dicha operación sobre el entero proporcionado:

// Es método ejecuta la función indicada por // el parámetro operacion, enviándole el valor especificado, // y retorna el resultado obtenido de la misma. Public int calcula(int valor, Func<int, int> operacion) { return operacion(valor); // retorna el resultado de aplicar la expresión indicada al valor. }

// Usos posibles: int i = calcula(4, x => x / 2); // Le pasamos una referencia a la // función que estamos definiendo sobre // la marcha. El resultado es que i=2.

int j = calcula(4, duplica); // Le pasamos la variable "duplica", // que es una referencia a la lambda // definida anteriormente. J valdrá 8. 

<HistoriaDelAbuelete>Seguro que a los más viejos del lugar esto le recuerda a los Codeblocks que utilizábamos en Clipper a principios de los 90 (uuf, cómo pasa el tiempo...). ¿Todavía reconocéis el siguiente código?

bDuplica := { |n| n*2 } ? EVAL(bDuplica, 7) // Muestra un 14 </HistoriaDelAbuelete>

Una consecuencia directa de que las expresiones lambdas sean referenciadas a través de delegados es que podemos utilizarlas en cualquier sitio donde se acepte un delegado, con la única precaución de escribirla teniendo en cuenta el tipo de su retorno y los parámetros que recibe. Un ejemplo claro lo tenemos en la suscripción a eventos, donde la técnica habitual consiste en utilizar un delegado a un método en el que se implementa la lógica del tratamiento de los mismos, algo como:

Page 52: Curso Linq

// Nos suscribimos al evento MouseMove: this.MouseMove += new MouseEventHandler(this.Form1_MouseMove); [...]

// Tratamiento del evento MouseMove: private void Form1_MouseMove(object sender, MouseEventArgs e) { this.Text = e.X + "," + e.Y; } Como sabemos, podemos suscribirnos al evento MouseMove añadiéndole delegados del tipo MouseEventHandler, definido en System.Windows.Forms, cuya firma indica que recibe un parámetro de tipo object, otro de tipo MouseEventArgs y no retorna ningún valor, exactamente igual que sería un delegado anónimo (C# 2.0) escrito así:

this.MouseMove += delegate(object sender, MouseEventArgs args) { this.Text = args.X + "," + args.Y; }; Y dado que las lambdas pueden sustituir de forma directa a cualquier delegado, podemos utilizarlas para conseguir un código más compacto:

this.MouseMove += (sender, args) => { this.Text = args.X + "," + args.Y; }; Llegados a este punto es conveniente aclarar que las expresiones lambda son características introducidas en los lenguajes, y por tanto en sus compiladores, pero no en la plataforma de ejecución (CLR) en sí. Por tanto, todo lo descrito hasta el momento era posible realizarlo antes que las lambda aparecieran por el horizonte, aunque de forma un poco más tediosa, utilizando mecanismos que la versión 2.0 del framework ponía a nuestra disposición, como los delegados y métodos anónimos. En este sentido, el uso de expresiones lambda aportan mucha simplicidad, elegancia y legibilidad al código.

Esto explica, además, que Visual Studio 2008 sea capaz de generar código para .NET 2.0 a partir de código fuente C# 3.0.

Tipos de delegados de expresiones lambdaAntes ya había adelantado que la definición Func<int, int> era simplemente una forma de indicar el tipo del parámetro que recibía la función lambda, así como el tipo del valor de retorno. En realidad, lo único que estábamos haciendo era definir, de forma muy sencilla y rápida, el delegado hacia la función.

Vamos a concretar esto un poco más, pero antes de continuar, una cosa: si para tí un genérico es un tipo de medicamento, mejor que leas algo sobre el tema antes de continuar, pues en caso contrario es posible que te pierdas un poco ;-). Puedes probar leyendo una introducción a los generics en c#, o

Page 53: Curso Linq

la Guía de programación de C#.

.NET Framework ofrece en el espacio de nombres System un conjunto de definiciones de genéricas de delegados para que podamos utilizarlos para "apuntar" hacia las funciones definidas mediante expresiones lambda, llamados Action y Func.

Utilizaremos los tipos Func para definir referencias a expresiones lambda que retornen un valor, o sea, funciones. De ahí su nombre. Los tipos Action, en cambio, están destinados a referenciar a lambdas que realicen acciones y que no retornen ningún valor. De ahí su nombre también. ;-)

Una de estas definiciones es la que habíamos usado en un ejemplo anterior:

Func<int, int> duplica = x => x * 2; Como se puede observar, al tratarse de una referencia a una función que retorna un valor, hemos utilizado un tipo Func con dos parámetros genéricos, que corresponde con la siguiente declaración existente en el espacio de nombres System:

Public delegate TResult Func<T, TResult>(T arg); Por ello, cuando declarábamos que la variable duplica era del tipo Func<int, int>, lo que indicábamos era, en primer lugar que el parámetro que necesitaba la lambda era un int, y que ésta nos devolvería también un int, es decir, lo mismo que si hubiéramos definido duplica así, utilizando métodos anónimos de C# 2.0:

// En el área de declaraciones: public delegate int Duplicador(int arg); ... // En el código: Duplicador duplica = delegate(int k) {return k*2 }; Obviamente, la sintaxis lambda es mucho más compacta y expresiva.

En la práctica, lo único que tenemos que tener claro a la hora de referenciar una función lambda es el tipo de cada uno de los parámetros que usa, y el tipo de retorno. Estos se introducen, en ese orden, en los parámetros genéricos de la clase Func y listo. Como esto debe quedar claro, ahí van unos ejemplos de definición y uso:

// Recibe un entero y retorna un booleano: Func<int, bool> esPar = x => x%2==0; Console.WriteLine(esPar(2)); // Muestra "True"

// Recibe dos enteros, retorna otro entero: Func<int, int, int> suma = (a,b) => a+b; Console.WriteLine(suma(2,3)); // Muestra "5"

// No recibe nada, retorna un texto: Func<string> hora = () => "Son las " + DateTime.Now.ToShortTimeString(); Console.WriteLine(hora()); // Muestra "Son las 14:21:10"

Page 54: Curso Linq

 Es importante saber que en el framework están definidos los delegados Func<tipo1, tipo2...,

tipoResult> para funciones de hasta cuatro parámetros. Si necesitamos más deberemos definir los delegados a mano, aunque esto es realmente sencillo utilizando una de las declaraciones existentes y añadiéndole el número de parámetros que deseemos. Por ejemplo, para seis parámetros la definición del genérico sería algo así como:

public delegate TResult Func<T1, T2, T3, T4, T5, T6, TResult> (T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6); Pero ahora aparece un pequeño problema: las funciones sin retorno no pueden referenciarse con delegados de tipo Func , puesto que el framework .NET no soporta la instanciación de tipos genéricos utilizando parámetros void (ECMA 335, sección 9.4, pág. 153). Por tanto, no podríamos declarar un delegado como Func<int, void> para apuntar hacia una función que recibe un entero y no devuelve nada. Si lo pensáis un poco, este es el motivo de que no exista ninguna sobrecarga de la clase Func sin parámetros genéricos, pues como mínimo debemos indicar el tipo del valor de retorno.

La clave para cubrir estos casos se encuentra en el tipo Action. Como comentaba unas líneas más arriba, el objeto de estos tipos de delegados es apuntar a expresiones lambda que realicen acciones y que no retornen ningún valor, por lo que sus parámetros genéricos describirán exclusivamente los tipos de los parámetros de la función. En este caso, como es obvio, sí existe una clase no parametrizada Action para apuntar a funciones sin parámetros, además de disponer de genéricos que cubren las acciones de hasta cuatro parámetros. Veamos unos ejemplos:

// Acción sin parámetros (no genérica): Action saluda = () => Console.WriteLine("hola"); saluda(); // Muestra "hola";

// Acción que recibe un string Action<string> apaga = motivo => { log(motivo); shutdown(); }; apaga("mantenimiento"); // Apaga el sistema Por último, me parece interesante recordar algo que había comentado en el post anterior, que en las expresiones lambda no era necesario indicar el tipo de los parámetros ni del retorno porque el compilador los infería del contexto. Como podemos ver, lo tiene bastante fácil, puesto que simplemente debe tomar la definición del delegado para conocerlos; por eso no es necesario introducir redundancias como las siguientes:

Func<int, int> duplica = (int a) => (int)(a * 2); // ¡Redundante!

// Forma más cómoda:

Func<int, int> duplica = a => a * 2; // Ok!

Page 55: Curso Linq

 En cualquier caso, si por algún motivo es necesario utilizar la forma explícita, sabed que no se permite hacerlo de forma parcial, es decir, o le ponéis los tipos a todo, o no se los ponéis a nada.

Page 56: Curso Linq

C#/.NET Little Wonders: The Generic Func Delegates

Once again, in this series of posts I look at the parts of the .NET Framework that may seem trivial, but can help improve your code by making it easier to write and maintain. The index of all my past little wonders posts can be found here.

Back in one of my three original “Little Wonders” Trilogy of posts, I had listed generic delegates as one of the Little Wonders of .NET.  Later, someone posted a comment saying said that they would love more detail on the generic delegates and their uses, since my original entry just scratched the surface of them.

Last week, I began our look at some of the handy generic delegates built into .NET with a description of delegates in general, and the Action family of delegates .  For this week, I’ll launch into a look at the Func family of generic delegates and how they can be used to support generic, reusable algorithms and classes.

Quick Delegate Recap

Delegates are similar to function pointers in C++ in that they allow you to store a reference to a method.  They can store references to either static or instance methods, and can actually be used to chain several methods together in one delegate.

Delegates are very type-safe and can be satisfied with any standard method, anonymous method, or a lambda expression.  They can also be null as well (refers to no method), so care should be taken to make sure that the delegate is not null before you invoke it.

Delegates are defined using the keyword delegate, where the delegate’s type name is placed where you would typically place the method name:

1: // This delegate matches any method that takes string, returns nothing

2: public delegate void Log(string message);

This delegate defines a delegate type named Log that can be used to store references to any method(s) that satisfies its signature (whether instance, static, lambda expression, etc.).

Delegate instances then can be assigned zero (null) or more methods using the operator = which replaces the existing delegate chain, or by using the operator += which adds a method to the end of a delegate chain:

1: // creates a delegate instance named currentLogger defaulted to Console.WriteLine (static method)

2: Log currentLogger = Console.Out.WriteLine;

3: 

4: // invokes the delegate, which writes to the console out

5: currentLogger("Hi Standard Out!");

Page 57: Curso Linq

6: 

7: // append a delegate to Console.Error.WriteLine to go to std error

8: currentLogger += Console.Error.WriteLine;

9: 

10: // invokes the delegate chain and writes message to std out and std err

11: currentLogger("Hi Standard Out and Error!");

While delegates give us a lot of power, it can be cumbersome to re-create fairly standard delegate definitions repeatedly, for this purpose the generic delegates were introduced in various stages in .NET.  These support various method types with particular signatures.

Note: a caveat with generic delegates is that while they can support multiple parameters, they do not match methods that contains ref or out parameters. If you want to a delegate to represent methods that takes ref or out parameters, you will need to create a custom delegate.

We’ve got the Func… delegates

Just like it’s cousin, the Action delegate family, the Func delegate family gives us a lot of power to use generic delegates to make classes and algorithms more generic.  Using them keeps us from having to define a new delegate type when need to make a class or algorithm generic.

Remember that the point of the Action delegate family was to be able to perform an “action” on an item, with no return results.  Thus Action delegates can be used to represent most methods that take 0 to 16 arguments but return void.  You can assign a method

The Func delegate family was introduced in .NET 3.5 with the advent of LINQ, and gives us the power to define a function that can be called on 0 to 16 arguments and returns a result.  Thus, the main difference between Action and Func, from a delegate perspective, is that Actions return nothing, but Funcs return a result.

The Func family of delegates have signatures as follows:

Func<TResult> – matches a method that takes no arguments, and returns value of type TResult.

Func<T, TResult> – matches a method that takes an argument of type T, and returns value of type TResult.

Func<T1, T2, TResult> – matches a method that takes arguments of type T1 and T2, and returns value of type TResult.

Func<T1, T2, …, TResult> – and so on up to 16 arguments, and returns value of type TResult.

These are handy because they quickly allow you to be able to specify that a method or class you design will perform a function to produce a result as long as the method you specify meets the signature.

Page 58: Curso Linq

For example, let’s say you were designing a generic aggregator, and you wanted to allow the user to define how the values will be aggregated into the result (i.e. Sum, Min, Max, etc…).  To do this, we would ask the user of our class to pass in a method that would take the current total, the next value, and produce a new total. 

A class like this could look like:

1: public sealed class Aggregator<TValue, TResult>

2: {

3: // holds method that takes previous result, combines with next value, creates new result

4: private Func<TResult, TValue, TResult> _aggregationMethod;

5: 

6: // gets or sets the current result of aggregation

7: public TResult Result { get; private set; }

8: 

9: // construct the aggregator given the method to use to aggregate values

10: public Aggregator(Func<TResult, TValue, TResult> aggregationMethod = null)

11: {

12: if (aggregationMethod == null) throw new ArgumentNullException("aggregationMethod");

13: 

14: _aggregationMethod = aggregationMethod;

15: }

16: 

17: // method to add next value

18: public void Aggregate(TValue nextValue)

19: {

20: // performs the aggregation method function on the current result and next and sets to current result

21: Result = _aggregationMethod(Result, nextValue);

22: }

23: }

Of course, LINQ already has an Aggregate extension method, but that works on a sequence of IEnumerable<T>, whereas this is designed to work more with aggregating single results over time (such as keeping track of a max response time for a service).

We could then use this generic aggregator to find the sum of a series of values over time, or the max of a series of values over time (among other things):

1: // creates an aggregator that adds the next to the total to sum the values

2: var sumAggregator = new Aggregator<int, int>((total, next) => total + next);

3: 

4: // creates an aggregator (using static method) that returns the max of previous result and next

5: var maxAggregator = new Aggregator<int, int>(Math.Max);

So, if we were timing the response time of a web method every time it was called, we could pass that response time to both of these aggregators to get an idea of the total time spent in that web method, and the max time spent in any one call to the web method:

1: // total will be 13 and max 13

2: int responseTime = 13;

3: sumAggregator.Aggregate(responseTime);

Page 59: Curso Linq

4: maxAggregator.Aggregate(responseTime);

5: 

6: // total will be 20 and max still 13

7: responseTime = 7;

8: sumAggregator.Aggregate(responseTime);

9: maxAggregator.Aggregate(responseTime);

10: 

11: // total will be 40 and max now 20

12: responseTime = 20;

13: sumAggregator.Aggregate(responseTime);

14: maxAggregator.Aggregate(responseTime);

The Func delegate family is useful for making generic algorithms and classes, and in particular allows the caller of the method or user of the class to specify a function to be performed in order to generate a result.

What is the result of a Func delegate chain?

If you remember, we said earlier that you can assign multiple methods to a delegate by using the += operator to chain them.  So how does this affect delegates such as Func that return a value, when applied to something like the code below?

1: Func<int, int, int> combo = null;

2: 

3: // What if we wanted to aggregate the sum and max together?

4: combo += (total, next) => total + next;

5: combo += Math.Max;

6: 

7: // what is the result?

8: var comboAggregator = new Aggregator<int, int>(combo);

Well, in .NET if you chain multiple methods in a delegate, they will all get invoked, but the result of the delegate is the result of the last method invoked in the chain.  Thus, this aggregator would always result in the Math.Max() result.  The other chained method (the sum) gets executed first, but it’s result is thrown away:

1: // result is 13

2: int responseTime = 13;

3: comboAggregator.Aggregate(responseTime);

4: 

5: // result is still 13

6: responseTime = 7;

7: comboAggregator.Aggregate(responseTime);

8: 

9: // result is now 20

10: responseTime = 20;

11: comboAggregator.Aggregate(responseTime);

So remember, you can chain multiple Func (or other delegates that return values) together, but if you do so you will only get the last executed result.

Page 60: Curso Linq

Func delegates and co-variance/contra-variance in .NET 4.0

Just like the Action delegate, as of .NET 4.0, the Func delegate family is contra-variant on its arguments.  In addition, it is co-variant on its return type.  To support this, in .NET 4.0 the signatures of the Func delegates changed to:

o Func<out TResult> – matches a method that takes no arguments, and returns value of type TResult (or a more derived type).

o Func<in T, out TResult> – matches a method that takes an argument of type T (or a less derived type), and returns value of type TResult(or a more derived type).

o Func<in T1, in T2, out TResult> – matches a method that takes arguments of type T1 and T2 (or less derived types), and returns value of type TResult (or a more derived type).

o Func<in T1, in T2, …, out TResult> – and so on up to 16 arguments, and returns value of type TResult (or a more derived type).

Notice the addition of the in and out keywords before each of the generic type placeholders.  As we saw last week, the in keyword is used to specify that a generic type can be contra-variant -- it can match the given type or a type that is less derived.  However, the out keyword, is used to specify that a generic type can be co-variant -- it can match the given type or a type that is more derived.

On contra-variance, if you are saying you need an function that will accept a string, you can just as easily give it an function that accepts an object.  In other words, if you say “give me an function that will process dogs”, I could pass you a method that will process any animal, because all dogs are animals. 

On the co-variance side, if you are saying you need a function that returns an object, you can just as easily pass it a function that returns a string because any string returned from the given method can be accepted by a delegate expecting an object result, since string is more derived.  Once again, in other words, if you say “give me a method that creates an animal”, I can pass you a method that will create a dog, because all dogs are animals.

It really all makes sense, you can pass a more specific thing to a less specific parameter, and you can return a more specific thing as a less specific result.  In other words, pay attention to the direction the item travels (parameters go in, results come out).  Keeping that in mind, you can always pass more specific things in and return more specific things out.

For example, in the code below, we have a method that takes a Func<object> to generate an object, but we can pass it a Func<string> because the return type of object can obviously accept a return value of string as well:

1: // since Func<object> is co-variant, this will access Func<string>, etc...

2: public static string Sequence(int count, Func<object> generator)

3: {

4: var builder = new StringBuilder();

Page 61: Curso Linq

5: 

6: for (int i=0; i<count; i++)

7: {

8: object value = generator();

9: builder.Append(value);

10: }

11: 

12: return builder.ToString();

13: }

Even though the method above takes a Func<object>, we can pass a Func<string> because the TResult type placeholder is co-variant and accepts types that are more derived as well:

1: // delegate that's typed to return string.

2: Func<string> stringGenerator = () => DateTime.Now.ToString();

3: 

4: // This will work in .NET 4.0, but not in previous versions

5: Sequence(100, stringGenerator);

Previous versions of .NET implemented some forms of co-variance and contra-variance before, but .NET 4.0 goes one step further and allows you to pass or assign an Func<A, BResult> to a Func<Y, ZResult> as long as A is less derived (or same) as Y, and BResult is more derived (or same) as ZResult.

Sidebar: The Func and the Predicate

A method that takes one argument and returns a bool is generally thought of as a predicate.  Predicates are used to examine an item and determine whether that item satisfies a particular condition.  Predicates are typically unary, but you may also have binary and other predicates as well.

Predicates are often used to filter results, such as in the LINQ Where() extension method:

1: var numbers = new[] { 1, 2, 4, 13, 8, 10, 27 };

2: 

3: // call Where() using a predicate which determines if the number is even

4: var evens = numbers.Where(num => num % 2 == 0);

As of .NET 3.5, predicates are typically represented as Func<T, bool> where T is the type of the item to examine.  Previous to .NET 3.5, there was a Predicate<T> type that tended to be used (which we’ll discuss next week) and is still supported, but most developers recommend using Func<T, bool> now, as it prevents confusion with overloads that accept unary predicates and binary predicates, etc.:

1: // this seems more confusing as an overload set, because of Predicate vs Func

2: public static SomeMethod(Predicate<int> unaryPredicate) { }

3: public static SomeMethod(Func<int, int, bool> binaryPredicate) { }

4: 

Page 62: Curso Linq

5: // this seems more consistent as an overload set, since just uses Func

6: public static SomeMethod(Func<int, bool> unaryPredicate) { }

7: public static SomeMethod(Func<int, int, bool> binaryPredicate) { }

Also, even though Predicate<T> and Func<T, bool> match the same signatures, they are separate types!  Thus you cannot assign a Predicate<T> instance to a Func<T, bool> instance and vice versa:

1: // the same method, lambda expression, etc can be assigned to both

2: Predicate<int> isEven = i => (i % 2) == 0;

3: Func<int, bool> alsoIsEven = i => (i % 2) == 0;

4: 

5: // but the delegate instances cannot be directly assigned, strongly typed!

6: // ERROR: cannot convert type...

7: isEven = alsoIsEven;

8: 

9: // however, you can assign by wrapping in a new instance:

10: isEven = new Predicate<int>(alsoIsEven);

11: alsoIsEven = new Func<int, bool>(isEven);

So, the general advice that seems to come from most developers is that Predicate<T> is still supported, but we should use Func<T, bool> for consistency in .NET 3.5 and above.

Sidebar: Func as a Generator for Unit Testing

One area of difficulty in unit testing can be unit testing code that is based on time of day.  We’d still want to unit test our code to make sure the logic is accurate, but we don’t want the results of our unit tests to be dependent on the time they are run.

One way (of many) around this is to create an internal generator that will produce the “current” time of day.  This would default to returning result from DateTime.Now (or some other method), but we could inject specific times for our unit testing.  Generators are typically methods that return (generate) a value for use in a class/method.

For example, say we are creating a CacheItem<T> class that represents an item in the cache, and we want to make sure the item shows as expired if the age is more than 30 seconds.  Such a class could look like:

1: // responsible for maintaining an item of type T in the cache

2: public sealed class CacheItem<T>

3: {

4: // helper method that returns the current time

5: private static Func<DateTime> _timeGenerator = () => DateTime.Now;

6: 

7: // allows internal access to the time generator

8: internal static Func<DateTime> TimeGenerator

9: {

10: get { return _timeGenerator; }

11: set { _timeGenerator = value; }

12: }

Page 63: Curso Linq

13: 

14: // time the item was cached

15: public DateTime CachedTime { get; private set; }

16: 

17: // the item cached

18: public T Value { get; private set; }

19: 

20: // item is expired if older than 30 seconds

21: public bool IsExpired

22: {

23: get { return _timeGenerator() - CachedTime > TimeSpan.FromSeconds(30.0); }

24: }

25: 

26: // creates the new cached item, setting cached time to "current" time

27: public CacheItem(T value)

28: {

29: Value = value;

30: CachedTime = _timeGenerator();

31: }

32: }

Then, we can use this construct to unit test our CacheItem<T> without any time dependencies:

1: var baseTime = DateTime.Now;

2: 

3: // start with current time stored above (so doesn't drift)

4: CacheItem<int>.TimeGenerator = () => baseTime;

5: 

6: var target = new CacheItem<int>(13);

7: 

8: // now add 15 seconds, should still be non-expired

9: CacheItem<int>.TimeGenerator = () => baseTime.AddSeconds(15);

10: 

11: Assert.IsFalse(target.IsExpired);

12: 

13: // now add 31 seconds, should now be expired

14: CacheItem<int>.TimeGenerator = () => baseTime.AddSeconds(31);

15: 

16: Assert.IsTrue(target.IsExpired);

Now we can unit test for 1 second before, 1 second after, 1 millisecond before, 1 day after, etc.  Func delegates can be a handy tool for this type of value generation to support more testable code. 

Summary

Generic delegates give us a lot of power to make truly generic algorithms and classes.  The Func family of delegates is a great way to be able to specify functions to calculate a result based on 0-16 arguments. 

Page 64: Curso Linq

Stay tuned in the weeks that follow for other generic delegates in the .NET Framework!

Crear peticiones LINQ1. Presentación

LINQ significa Language INtegrated Query. Desde el punto de vista del desarrollador, se trata de un lenguaje de consulta que permite realizar peticiones a fuentes de datos de diferente naturaleza:

Utilización de Linq en aplicaciones .NET

Antes de realizar peticiones a un modelo de entidades, es fundamental saber crear y ejecutar peticiones en un grupo de objetos mediante Linq To Objects.

2. Autopsia de una petición LINQ To Objects

Una petición Linq se compone de cláusulas, y cada una de ellas tiene una función definida. A continuación se muestran algunas de estas cláusulas:

From …: permite declarar los objetos utilizados en la petición. In …: permite especificar los conjuntos de objetos fuente. Where …: permite filtrar los objetos que se devolverán. Orderby …: permite ordenar los objetos que se devolverán. Group … by … into …: permite realizar una agrupación de datos. Select: permite especificar los objetos/datos que debe devolver la petición.

Page 65: Curso Linq

A continuación se muestra un ejemplo de petición LINQ que obtiene información de los procesos que están en ejecución en un ordenador:

var lisListaProcesos = (from oProceso in Process.GetProcesses()  where oProceso.WorkingSet64 > 20 * 1024 * 1024  orderby oProceso.ProcessName descending  select new {oProceso.Id, Nombre = oProceso.ProcessName}  ).ToList();

Esta petición permite obtener el identificador y la etiqueta de aquellos procesos que están en ejecución en un ordenador cuya cantidad de memoria asignada es estrictamente superior a 20 MB. Además, devuelve los registros por orden alfabético inverso según su etiqueta.

Se utilizarán las peticiones LINQ en la implementación de reglas y servicios y procesamientos de negocio en nuestras aplicaciones.

3. Los operadores de petición

Las peticiones LINQ devuelven un conjunto de datos que puede tener la forma de un objeto/de un dato o de un conjunto de objetos/de datos. Para poder obtener estos datos, un subconjunto o incluso aquellos que verifiquen cierta condición, el Framework .NET ofrece varios operadores de petición implementados en forma de métodos de extensión. A continuación se muestran algunos de ellos que se pueden aplicar a una petición LINQ realizada sobre un grupo de objetos:

ToList(): permite obtener el conjunto de objetos devuelto por la petición en forma de una colección genérica.

First(): permite obtener el primer objeto devuelto por la petición. FirstOrDefault(): permite obtener el primer objeto devuelto por la petición. Si la

petición no devuelve objetos, entonces es el valor por defecto del tipo de objeto el que se devuelve.

Last(): permite obtener el último objeto devuelto por la petición. Count(): permite obtener el número de objetos devuelto por la petición. Where(): permite obtener un subconjunto de objetos que cumplan una condición. OrderBy(): permite ordenar los objetos. Select(): permite realizar una proyección de datos sobre los objetos o datos que

contienen.

Se pueden usar estos operadores de petición para escribir un procesamiento idéntico a la petición LINQ generada anteriormente:

var lisListaProcesos = Process.GetProcesses()  .Where(oProceso => oProceso.WorkingSet64 > 20 * 1024 * 1024)  .OrderByDescending(oProceso => oProceso.ProcessName)  .Select(oProcess => new { oProceso.Id, Nombre = oProceso.ProcessName }) .ToList();

Page 66: Curso Linq

En esta instrucción, la utilización de operadores de petición requiere el uso de expresiones lambda para definir una expresión booleana que permita filtrar, una propiedad de ordenación y seleccionar los datos que se desean devolver.

Page 67: Curso Linq

LINQ Tutorial for BeginnersLINQ

LINQ is Microsoft’s technology to provide a language-level support mechanism for querying data of all types. These types include in memory arrays and collections, databases, XML documents and more, since version 3.5 and Visual Studio 2008. (.NET 4 and Visual Studio 2010 added support for the Parallel LINQ features).

Need for LINQ

Here is the issue that we cannot programmatically interact with a database at the native language level. This means syntax errors often go undetected until runtime.

Differing data types utilized by a particular data domain, such as database or XML data types versus the native language

XML parsing, iterating, and manipulation can be quite tedious. an XmlDocument must be created just to perform various operations on the XML fragment

Advantages of LINQ

Query is integrated into the language. Gone are the days of writing a SQL query into a string and not detecting a syntax error until runtime, for example we forget the name of a field of the table (or reference) or it has been changed in DB.

In addition to query features, LINQ to XML provides a more powerful and easier-to-use interface for working with XML data, as though it were a database.

Example:

XElement books = XElement.Parse( @"<books> <book> <title>Pro LINQ: Language Integrated Query in C#2010</title> <author>Joe Rattz</author> </book> <book> <title>Pro .NET 4.0 Parallel Programming in C#</title> <author>Adam Freeman</author> </book> <book> <title>Pro VB 2010 and the .NET 4.0 Platform</title> <author>Andrew Troelsen</author> </book> </books>");

//XElement Xbooks = XElement.Parse(@"XMLFile.xml");var titles =from book in books.Elements("book")where (string)book.Element("author") == "Joe Rattz"select book.Element("title");

Page 68: Curso Linq

foreach (var title in titles) Console.WriteLine(title.Value);

Not only for querying data but for formatting, validating, and even getting data into the necessary format : example string array to integer array and sort. can also use select new for complex classes

Example:

string[] numbers = { "0042", "010", "9", "27" }; int[] nums = numbers.Select( s => Int32.Parse(s)).OrderBy(s => ).ToArray(); foreach (int num in nums) Console.WriteLine(num);

Syntax of LINQ

Two syntaxes are available for LINQ queries:

Query expression syntax

from str in strings where str.Length==3 select str;

Standard dot notation syntax

stringList.Where(s => s.Length == 3).Select(s=>s);

Type of LINQ

LINQ to Objects LINQ to XML LINQ to DataSet LINQ to SQL LINQ to Entities.

More about LINQ They are queries returning a set of matching objects, a single object, or a subset of fields

from an object or set of objects. In LINQ, this returned set of objects is called a sequence, and most LINQ sequences are of type IEnumerable<T>.

We can use the "Cast" or "OfType" operators for Legacy Collections to convert them to IEnumerable to use LINQ.

The LINQ query actually take place the first time a result from it is needed. This is typically when the query results variable is enumerated.

And this may lead to the situation: deferred query is passed undetected with error.--> deferred query example (disadvantage)

Example:

Page 69: Curso Linq

string[] strings = { "one", "two", null, "three" };Console.WriteLine("Before Where() is called.");IEnumerable<string> ieStrings = strings.Where(s => s.Length == 3);Console.WriteLine("After Where() is called."); foreach (string s in ieStrings) { Console.WriteLine("Processing " + s); }

Calling the actual query each time is needless work. It might make more sense to have a query initialization method that gets called once for the lifetime of the scope and to construct all the queries there (advantage).

List<string> strings = new List<string>(); strings.Add("one"); strings.Add("two"); strings.Add("three");

IEnumerable<string> ieStrings = strings.Where(s => s.Length == 3); foreach (string s in ieStrings) { Console.WriteLine("Processing " + s); }

Console.ReadKey(); strings.Add("six"); Console.WriteLine("source enumerable changed but query is not invoked again"); //query is not invoked explicitly, ieStrings is not changes foreach (string s in ieStrings) { Console.WriteLine("Processing " + s); }

In Linq To Entity, string can be passed in where clause as a condition using “it” as variable refenrence.

Example:

VCAB_CMS_DBEntities context = new VCAB_CMS_DBEntities(); string condition = "it.DocName=='Shakuntala Devi'"; int pageCount= context.EDOC.Where(condition).Select(c => c.DocPageCount).First();

Language additions with LINQ

Lambda expressionsi => ((i & 1) == 1)

This expression refers to an anonymous method with left side as input to the method and right side as the output.

Expression treesIEnumerable<int> numsLessThanFour = nums.Where(i => i < 4).OrderBy(i => i);

Page 70: Curso Linq

The Where operator is called first, followed by the OrderBy operator. But an expression tree allows the simultaneous evaluation and execution of all operators in a query, a single query can be made instead of a separate query for each operator.

The keyword var, object and collection initialization, and anonymous types var address = new { address = "105 Elm Street", city = "Atlanta", state = "GA", postalCode = "30339" };

Compiler generated anonymous class name looks like: <>f__AnonymousType5`4[System.String,System.String,System.String,System.String].

Collection initialization allows you to specify the initialization values for a collection, just like you would for an object:

List<string> presidents = new List<string> { "Adams", "Arthur", "Buchanan" };

Extension methods

Used to extend a sealed class like adding factorial method in int class or adding todouble method in string class.

Extension methods are methods that, although static, can be called on an instance (object) of a class rather than on the class itself.

Specifying a method’s first argument with the “this” keyword modifier will make that method an extension method.

Extension methods can be declared only in static classes.

public static class ExtendsStringClass{ public static double ToDouble(this string s){ return Double.Parse(s); } }

class Program{ static void Main(string[] args){ double pi = "3.1415926535".ToDouble(); Console.WriteLine(pi); MyWidget myWidget = new MyWidget(); Console.ReadKey(); } }

Partial methods

A partial method can exist only in a partial class A partial method must return void. Partial methods are private but must not specify the private modifier

Example: To make the generated entity classes more usable, partial methods have been added to them. You can add another module that declares the same entity class, implement these partial methods, and be notified every time a property is about to be changed and after it is changed

Page 71: Curso Linq

Query expressions

Query expressions allow LINQ queries to be expressed in nearly SQL form, with just a few minor deviations.

The “from” statement precedes the select statement, hence intelliSense has the scope of what variables to offer you for selection.

Page 72: Curso Linq

Introducing LINQ – Part 1

Published: 3/12/2007By: Granville Barnett

Introducing LINQ is the first part of a series of articles on Language Integrated Query (LINQ). This series will cover the core essentials of LINQ and its use with other technologies like ASP.NET, Win Forms and WPF.

This and the forthcoming articles are designed to be a comprehensive tutorial on LINQ, having completed the series you will have a thorough understanding of LINQ and C# 3.0.

All code in the series will use the latest publicly available CTP at the time of writing.

Introducing LINQ Series Part 1 In this part you will learn how to the query in-memory collections.

Part 2 In this part we will look at querying relational data.

Part 3 In this part we will look a little more at what entities are, as well as taking a closer look at the key types we can use and their application.

Part 4 In this part of the series we will use LINQ, ASP.NET and ASP.NET AJAX to replicate the to-do list that Scott Guthrie created a while back to show off the features of ASP.NET AJAX.

Part 5 In this part of the series I will explain the DataContext class in depth through a series of examples and explanations.

Introducing LINQ – Part 1

In this article we will cover only the querying of in-memory collections, in future parts we will look at using LINQ with relational data (LINQ to SQL) and XML (LINQ to XML).

This article has been designed to give you a core understanding of LINQ that we will rely heavily on in subsequent parts of this series.

Before diving into the code it is essential to define what LINQ actually is. LINQ is not C# 3.0, and vice versa. LINQ relies heavily on the new language enhancements introduced in C# 3.0; however, LINQ essentially is the composition of many standard query operators that allow you to work with data in a more intuitive way regardless of the data source.

The benefits of using LINQ are significant – queries are a first class citizen within the C# language, benefit from compile time checking of queries, and the ability to debug (step through) queries. We can expect the next Visual Studio IDE to take full advantage of these benefits – certainly the March 2007 CTP of Visual Studio Orcas does!

Page 73: Curso Linq

In-Memory Collections

The best way to teach new technologies is to just to show you an example and then explain what the heck is going on! – That will be my approach throughout this series; hopefully it is a wise decision.

For our first example we will compose a query to retrieve all the items in a generic List collection (Fig. 1).

Figure 1: Selecting all the items in a generic List collection01.private static List<string> people = new List<string>()

02.{

03."Granville", "John", "Rachel", "Betty",

04."Chandler", "Ross", "Monica"

05.};

06. 

07.public static void Example1()

08.{

09.IEnumerable<string> query = from p in people select p;

10.foreach (string person in query)

11.{

12.Console.WriteLine(person);

13.}

14.}

The code example given in Fig. 1 is very basic and its functionality could have been replicated easier by simply enumerating through the items in the List via a foreach loop.

In Fig.1 we compose a query that will return each of the items in the people List collection by aliasing the people collection with a variable p and then selecting p (p is of type string remember as the people List is a collection of immutable string objects).

You may notice that query is of type IEnumerable<string> - this is because we know that query will hold an enumeration of type string. When we foreach through the query the GetEnumerator of query is invoked.

Page 74: Curso Linq

At this time it is beneficial to look at exactly what the compiler generated code looks like (Fig. 2).

Figure 2: Compiler generated code for Fig. 101.public static void Example1()

02.{

03.IEnumerable<string> query = people.Select<string, string>(delegate (string p)

04.{

05.return p;

06.});

07.foreach (string person in query)

08.{

09.Console.WriteLine(person);

10.}

11.}

Fig. 2 reveals that our query has actually been converted by the compiler to use an extension method (in this case just the Select extension method is used) taking a delegate as its argument.

You will find that queries and lambda expressions are simply a facade that we deal with in order to make our lives easier – under the covers the compiler is generating the appropriate code using delegates. Be aware of this internal compiler behavior!

Also be aware that a cached anonymous delegate method is generated at compile time as well (Fig. 3) – we will discuss this particular feature in future articles.

Figure 3: Compiler generated cached anonymous delegate method1.[CompilerGenerated]

2.private static Func<string, string> <>9__CachedAnonymousMethodDelegate1;

We will now take a look at a more complex query of the same collection which retrieves a sequence of all strings in the List whose length is greater than 5(Fig. 4).

Figure 4: A more complex query01.public static void Example2()

02.{

03.IEnumerable<string> query = from p in people where p.Length > 5

Page 75: Curso Linq

04.orderby p select p;

05. 

06.foreach (string person in query)

07.{

08.Console.WriteLine(person);

09.}

10.}

The example in Fig. 4 relies on the use of two other standard query operators – Where and orderby to achieve the desired results.

If we examine the code generated by the compiler for the Example2 method you will see that shown in Fig. 5 – notice as well that we now have another two cached anonymous delegate methods (Fig. 6) – each of which having the type signature of their corresponding delegates (Where delegate and orderby delegate).

Figure 5: Compiler generated code for Fig. 401.public static void Example2()

02.{

03.IEnumerable<string> query = people.Where<string>(delegate (string p)

04.{

05.return (p.Length > 5);

06.}).OrderBy<string, string>(delegate (string p)

07.{

08.return p;

09.});

10.foreach (string person in query)

11.{

12.Console.WriteLine(person);

13.}

14.}

Page 76: Curso Linq

Figure 6: Cached anonymous delegate methods for their respective Where and orderby delegates defined in Fig. 51.[CompilerGenerated]

2.private static Func<string, bool> <>9__CachedAnonymousMethodDelegate4;

3.[CompilerGenerated]

4.private static Func<string, string> <>9__CachedAnonymousMethodDelegate5;

The type signature of the Where delegate (Fig. 5) is Func. The delegate takes a string argument and returns a bool depending on whether the string was greater than 5 characters in length. Similarly the orderby delegate (Fig. 5) takes a string argument and returns a string.

I encourage you to further explore the querying of collections – I have blogged extensively on the subject (http://gbarnett.org/archive/tags/LINQ/default.aspx).

Standard Query Operators

For completeness I will briefly cover what the standard query operators entail.

When using LINQ with any supported data source (in-memory, relational data, XML) we can make use of a set of a standard query operators which empower us to manipulate our data source more effectively. A few standard query operators include:

Select OrderBy Where SelectAll TakeWhile Take Skip First SkipWhile ...

There are a tonne of standard query operators and I advise you to explore the use of each to gain a richer understanding of how to deal with data.

We will cover many of the standard query operators in future parts of this series.

Lambda Expressions

Lambda expressions provide a clearer syntax for anonymous delegates – in this section we will replicate the code in Fig. 4 by using lambda expressions and extension methods (Fig. 6).

Figure 6: Same example as Fig. 4 but using lambda expression and extension methods1.public static void Example3()

Page 77: Curso Linq

2.{

3.IEnumerable<string> query = people.Where(x => x.Length > 5).OrderBy(x => x);

4.foreach (string person in query)

5.{

6.Console.WriteLine(person);

7.}

8.}

A lambda expression normally takes the form of arguments => expression, the expression is always preceded by the => token. If you want to have a lambda expression with more than one argument you must enclose the arguments in parentheses delimited by a comma.

If you noticed in Figs 2 and 5 the compiler generated code actually uses extension methods not a query – this is purely an implementation detail, much like the use of lambda expressions in Fig. 6 will be converted to anonymous delegates by the compiler (Fig. 7).

Figure 7: Compiler generated code for Fig. 601.public static void Example2()

02.{

03.IEnumerable<string> query = people.Where<string>(delegate (string p)

04.{

05.return (p.Length > 5);

06.}).OrderBy<string, string>(delegate (string p)

07.{

08.return p;

09.});

10.foreach (string person in query)

11.{

12.Console.WriteLine(person);

13.}

14.}

We will use lambda extensions extensively in future parts of this series.

Page 78: Curso Linq

Summary

In this article we looked at some examples of using LINQ with queries, and extension methods as well as looking at the compiler generated code.

Please explore the standard query operator library and investigate the code generated by the compiler as the next wave of language compilers inject an awful lot of code behind the scenes that you will not be aware of unless you disassemble your code.

Page 79: Curso Linq

LINQ to Entities: Basic Concepts and FeaturesIntroduction

In my first three articles on CodeProject.com, I have explained the fundamentals of Windows Communication Foundation (WCF), including:

Implementing a Basic Hello World WCF Service Implementing a WCF Service with Entity Framework Concurrency Control of a WCF Service with Entity Framework

From early this year, I have started to write a series of articles to explain LINQ, LINQ to SQL, Entity Framework, and LINQ to Entities. Followings are the articles I wrote or plan to write for LINQ, LINQ to SQL, and LINQ to Entities:

Introducing LINQ—Language Integrated Query LINQ to SQL: Basic Concepts and Features LINQ to SQL: Advanced Concepts and Features (last article) LINQ to Entities: Basic Concepts and Features (this article) LINQ to Entities: Advanced Concepts and Features (next article)

And as I said, after finishing these five articles, I will come back to write some more articles on WCF from my real work experience, which will be definitely helpful to your real world work, if you are using WCF right now.

Overview

In the previous article (Introducing LINQ—Language Integrated Query), we learned the new features of C# 3.0 including LINQ. In this article and the next, we will see how to use LINQ to query a database, or in other words, how to use LINQ to Entities in C#. After reading these two articles, you will have a good understanding of LINQ to Entities, so that you can write the data access layer of your WCF service with LINQ to Entities, to securely, and reliably communicate with the underlying database.

In this article, we will cover the basic concepts and features of LINQ to Entities, which include:

What ORM is What LINQ to Entities is What LINQ to SQL is Comparing LINQ to Entities with LINQ to Objects and LINQ to SQL Modeling the Northwind database with LINQ to EntitiesQuerying and updating a database

with a table Deferred execution

Page 80: Curso Linq

Lazy loading and eager loading Joining two tables Querying with a view

In the next article, we will cover the advanced concepts and features of LINQ to Entities, such as Stored Procedure support, inheritance, simultaneous updating, and transaction processing.

ORM—Object-Relational Mapping

LINQ to Entities is considered to be one of Microsoft's new ORM products. So before we start explaining LINQ to Entities, let us first understand what ORM is.

ORM stands for Object-Relational Mapping. Sometimes it is called O/RM, or O/R mapping. It is a programming technique that contains a set of classes that map relational database entities to objects in a specific programming language.

Initially, applications could call specified native database APIs to communicate with a database. For example, Oracle Pro*C is a set of APIs supplied by Oracle to query, insert, update, or delete records in an Oracle database from C applications. The Pro*C pre-compiler translates embedded SQL into calls to the Oracle runtime library (SQLLIB).

Then, ODBC (Open Database Connectivity) was developed to unify all of the communication protocols for various RDBMSs. ODBC was designed to be independent of programming languages, database systems, and Operating Systems. So with ODBC, one application can communicate with different RDBMSs by using the same code, simply by replacing the underlying ODBC drivers.

No matter which method is used to connect to a database, the data returned from a database has to be presented in some format in the application. For example, if an Order record is returned from the database, there has to be a variable to hold the Order number, and a set of variables to hold the Order details. Alternatively, the application may create a class for the Orders, and another class for Order details. When another application is developed, the same set of classes may have to be created again, or if it is designed well, they can be put into a library, and re-used by various applications.

This is exactly where ORM fits in. With ORM, each database is represented by an ORM context object in the specific programming language, and database entities such as tables are represented by classes, with relationships between these classes. For example, the ORM may create an Order class to represent the Order table, and an OrderDetail class to represent the Order Details table. The Order class will contain a collection member to hold all of its details. The ORM is responsible for the mappings and the connections between these classes and the database. So, to the application, the database is now fully-represented by these classes. The application only needs to deal with these classes, instead of with the physical database. The application does not need to worry about how to connect to the database, how to construct the SQL statements, how to use the proper locking mechanism

Page 81: Curso Linq

to ensure concurrency, or how to handle distributed transactions. These database-related activities are handled by the ORM.

Entity Framework

Since LINQ to Entities is based on the Entity Framework, let’s explain what Entity Framework is now.

ADO.NET Entity Framework (EF) is a new addition to the Microsoft ADO.NET family. It enables developers to create data access applications by programming against a conceptual application model instead of programming directly against a relational storage schema. The goal is to decrease the amount of code and maintenance required for data-oriented applications. Entity Framework applications provide the following benefits:

Applications can work in terms of a more application-centric conceptual model, including types with inheritance, complex members, and relationships.

Applications are freed from hard-coded dependencies on a particular data engine or storage schema.

Mappings between the conceptual model and the storage-specific schema can change without changing the application code.

Developers can work with a consistent application object model that can be mapped to various storage schemas, possibly implemented in different database management systems.

Multiple conceptual models can be mapped to a single storage schema. Language-integrated query (LINQ) support provides compile-time syntax validation for

queries against a conceptual model.

With Entity Framework, developers work with a conceptual data model, an Entity Data Model, or EDM, instead of the underlying databases. The conceptual data model schema is expressed in the Conceptual Schema Definition Language (CSDL), the actual storage model is expressed in the Storage Schema Definition Language (SSDL), and the mapping in between is expressed in the Mapping Schema Language (MSL). A new data-access provider, EntityClient, is created for this new framework but under the hood, the ADO.NET data providers are still being used to communicate with the databases. The diagram below shows the high level architectures of Entity Framework.

Page 82: Curso Linq

LINQ to Entities

Now let’s have a look at what LINQ to Entities is.

LINQ to Entities provides Language-Integrated Query (LINQ) support that enables developers to write queries against the Entity Framework conceptual model using Visual Basic or Visual C#. Queries against the Entity Framework are represented by command tree queries, which execute against the object context. LINQ to Entities converts Language-Integrated Queries (LINQ) queries to command tree queries, executes the queries against the Entity Framework, and returns objects that can be used by both the Entity Framework and LINQ.

LINQ to Entities allows developers to create flexible, strongly-typed queries against the Entity Data Model (EDM) by using LINQ expressions and standard LINQ query operators. To certain degrees, LINQ to Entities is similar to LINQ to SQL, but LINQ to Entities is a true ORM product from Microsoft, and it supports more features than LINQ to SQL, such as multiple-table inheritance. LINQ to Entities also supports many other mainstream RDBMSs such as Oracle, DB2, and MySQL in addition to Microsoft SQL Server.

Page 83: Curso Linq

Comparing LINQ to Entities with LINQ to Objects

In the previous article, we used LINQ to query in-memory objects. Before we dive further into the world of LINQ to Entities, we first need to look at the relationship between LINQ to Entities and LINQ to Objects.

Some key differences between LINQ to Entities and LINQ to Objects are:

LINQ to Entities needs an Object Context object. The ObjectContext object is the bridge between LINQ and the database (we will explain more about ObjectContext later). LINQ to Objects don't need any intermediate LINQ provider or API.

LINQ to Entities returns data of type IQueryable<T> whereas LINQ to Objects returns data of type IEnumerable<T>.

LINQ to Entities queries are translated to SQL by way of Expression Trees, which allow them to be evaluated as a single unit, and translated to appropriate and optimal SQL Statements. LINQ to Objects queries do not need to be translated.

LINQ to Entities queries are translated to SQL calls and executed on the specified database while LINQ to Objects queries are executed in the local machine memory.

The similarities shared by all aspects of LINQ are the syntax. They all use the same SQL-like syntax and share the same groups of standard query operators. From the language syntax perspective, working with a database is the same as working with in-memory objects.

LINQ to SQL

Before LINQ to Entities, Microsoft released another ORM product, which is LINQ to SQL. Both LINQ to SQL and LINQ to Entities can be used in the data access layer to interact with databases, but they are quite different. In this section, we will explain what LINQ to SQL is, and in the next section, we will compare these two technologies.

In short, LINQ to SQL is a component of .NET Framework 3.5 that provides a run-time infrastructure for managing relational data as objects.

In LINQ to SQL, the data model of a relational database is mapped to an object model expressed in the programming language of the developer. When the application runs, LINQ to SQL translates language-integrated queries in the object model into SQL, and sends them to the database for execution. When the database returns the results, LINQ to SQL translates the results back to objects that you can work with in your own programming language.

Unlike LINQ to Entities, with LINQ to SQL, developers don’t need to create an extra data model between their applications and the underlying database. Under the hood of LINQ to SQL, ADO.NET SqlClient adapters are used to communicate with the actual SQL Server databases.

The following diagram shows the use of LINQ to SQL in a .NET application:

Page 84: Curso Linq

Comparing LINQ to SQL with LINQ to Entities

Now we know what LINQ to Entities is, and what LINQ to SQL is. In this section, let’s compare these two technologies.

As described earlier, LINQ to Entities applications work against a conceptual data model (EDM). All mappings between the languages and the databases go through the new EntityClient mapping provider. The application no longer connects directly to a database, or sees any database-specific constructs. The entire application operates in terms of the higher-level EDM.

This means that you can no longer use the native database query language. Not only will the database not understand the EDM model, but also current database query languages do not have the constructs required to deal with the elements introduced by the EDM, such as inheritance, relationships, complex-types, and so on.

On the other hand, for developers who do not require mapping to a conceptual model, LINQ to SQL enables developers to experience the LINQ programming model directly over the existing database schema.

LINQ to SQL allows developers to generate .NET classes that represent data. Rather than map to a conceptual data model, these generated classes map directly to database tables, views, Stored Procedures, and user defined functions. Using LINQ to SQL, developers can write code directly against the storage schema using the same LINQ programming pattern as was previously described for in-memory collections, Entities, or the Data Set, as well as for other data sources such as XML.

Page 85: Curso Linq

Compared to LINQ to Entities, LINQ to SQL has some limitations, mainly because of its direct mapping against the physical relational storage schema. For example, you can't map two different database entities into one single C# or VB object, and if the underlying database schema changes, this might require significant client application changes.

So, in a summary, if you want to work against a conceptual data model, use LINQ to Entities. If you want to have a direct mapping to the database from your programming languages, use LINQ to SQL.

The following table lists some of the features supported by these two data access methodologies:

Features LINQ to SQL LINQ to Entities

Conceptual Data Model No Yes

Storage Schema No Yes

Mapping Schema No Yes

New Data Access Provider No Yes

Non-SQL Server Database Support No Yes

Direct Database Connection Yes No

Language Extensions Support Yes Yes

Stored Procedures Yes Yes

Single-table Inheritance Yes Yes

Multiple-table Inheritance No Yes

Single Entity from Multiple Tables No Yes

Lazy Loading Support Yes Yes

Interestingly, some say LINQ to SQL was an intermediate solution. Fact is that LINQ to SQL was made by the C# team, instead of the ADO.NET team. It was of great importance for the C# team to release an O/RM mapper together with their new LINQ technology. Without a LINQ to databases implementation, the C# team would have a hard time evangelizing LINQ.

In November 2008, the ADO.NET team announced that Microsoft will continue to make some investments in LINQ to SQL, but they also made it pretty clear that LINQ to Entities is the recommended data access solution in future frameworks. Microsoft will invest

Page 86: Curso Linq

heavily in the Entity Framework. So in this book, we will use LINQ to Entities in our data access layer.

Creating a LINQ to Entities Test Application

Now that we have learned some of the basic concepts of LINQ to Entities, let us start exploring LINQ to Entities with some real examples. We will apply the skills we are going to learn in the following two articles to the data access layer of our WCF service, so that from the WCF service we can communicate with the database using LINQ to Entities, instead of the raw ADO.NET data adapter.

First, we need to create a new project to test LINQ to Entities. Just follow these steps to add this test application to the solution:

1. Open the solution TestLINQ2. From Solution Explorer, right-click on the Solution item and select Add | New Project…

from the context menu3. Select Visual C# | Console Application as the project template, enter

TestLINQToEntitiesApp as the (project) Name, and leave the default value C:\SOAwithWCFandLINQ\Projects\TestLINQ as the Location

4. Click OK

Creating the Data Model

To use LINQ to Entities, we need to add a conceptual data model—an Entity Data Model, or EDM – to the project. There are two ways to create the EDM, create from a database, or create manually. Here we will create the EDM from the Northwind database. We will add two tables and one view from the Northwind database into our project, so that later on we can use them to demonstrate LINQ to Entities.

Preparing the Northwind Database

Before you can create the EDM, you need to have a SQL Server database with the sample database Northwind installed. You can just search "Northwind sample database download", then download and install the sample database. If you need detailed instructions as how to download/install the sample database, you can refer to the section "Preparing the Database" in one of my previous articles, Implementing a WCF Service with Entity Framework".

Adding a LINQ to Entities Item to the Project

To start with, let us add a new item to our project TestLINQToEntitiesApp. The new item added should be of type ADO.NET Entity Data Model, and named Northwind.edmx, as shown in the following Add New Item dialog window:

Page 87: Curso Linq

After you click the Add button, the Entity Data Model Wizard window will pop up. Follow these steps to finish this wizard:

1. On the Choose Model Contents page, select Generate from database. Later we will connect to the Northwind database and let Visual Studio generate the conceptual data model for us. If you choose the Empty model option here, you will have to manually create the data model, which may be applicable sometimes, like you may not have a physical database when you do the modeling. You may even create your physical database from your model later if you choose this option and have finished your model.

2. Click Next on this window.

Page 88: Curso Linq

3. Now the Choose Your Data Connection window should be displayed. Since this is our first LINQ to Entities application, there is no existing data connection to choose from, so let’s click button New Connection … and set up a new data connection.

a. First choose Microsoft SQL Server as the data source, and leave .NET Framework Data Provider for SQL Server as the data provider. Click OK to close this window.

Page 89: Curso Linq

b. The Connection Properties window should be displayed on the screen. On this window, enter your database server name, together with your database instance name if your database instance is not the default one on your server. If it is on your machine, you can enter localhost as the server name.

c. Then specify the logon to your database.d. Click Test Connection to test your database connection settings. You should get a

“Test connection succeeded” message. If not, modify your server name or logon details, and make sure your SQL Server service is started. If your SQL Server is on another computer and your firewall is turned on, remember to enable the SQL Server port on the SQL Server machine.

e. Now select Northwind as the database name. If you don’t see Northwind in the database list, you need to install it to your SQL Server (refer to the previous article for installation details).

The Connection Properties window should be like this now:

Page 90: Curso Linq

f. Click OK on the Connection Properties window to go back to the Entity Data Model Wizard.

The Entity Data Model Wizard should be like this now:

Page 91: Curso Linq

4. On the Choose Your Database Objects page, select table Products, Categories, and view Current Product List, then click Finish:

Page 92: Curso Linq

After you click Finish, the following two files will be added to the project: Northwind.edmx and Northwind.designer.cs. The first file holds the model of the entities, including the entity sets, entity types, conceptual models, and the mappings. The second one is the code for the model, which defines the ObjectContext of the model.

At this point, the Visual Studio LINQ to Entities designer should be open and as shown in the following image:

Page 93: Curso Linq

Generated LINQ to Entities Classes

If you open the file Northwind.Designer.cs (you need to switch from the Model Browser to the Solution Explorer to open this file), you will find that the following classes have been generated for the project:

public partial class NorthwindEntities : ObjectContextpublic partial class Product : EntityObjectpublic partial class Category : EntityObjectpublic partial class Current_Product_List : EntityObject

In the above four classes, the NorthwindEntities class is the main conduit through which we'll query entities from the database, as well as apply changes back to it. It contains various flavors of types and constructors, partial validation methods, and property members for all of the included tables. It inherits from the ObjectContext class, which represents the main entry point for the LINQ to Entities framework.

The next two classes are for the two tables that we are interested in. They implement the EntityObject interface. This interface defines all of the related property changing, and

Page 94: Curso Linq

property changed event methods, which we can extend to validate properties before and after the change.

The last class is for the view. This is a simple class with only two property members. Because we are not going to update the database through this view, it doesn't define any property change or changed event method.

Querying and Updating the Database with a Table

Now that we have the entity classes created, we will use them to interact with the database. We will first work with the products table to query and update records, as well as to insert and delete records.

Querying Records

First, we will query the database to get some products.

To query a database using LINQ to Entities, we first need to construct an ObjectContext object, like this:

NorthwindEntities NWEntities = new NorthwindEntities();

We can then use LINQ query syntax to retrieve records from the database:

IEnumerable<Product> beverages = from p in NWEntities.Products where p.Category.CategoryName == "Beverages" orderby p.ProductName select p;

The preceding code will retrieve all of the products in the Beverages category, sorted by product name.

You can use this statement to print out the total number of beverage products in the Northwind database:

Console.WriteLine("There are {0} Beverages", beverages.Count());

Updating Records

We can update any of the products that we have just retrieved from the database, like this:

// update a productProduct bev1 = beverages.ElementAtOrDefault(10);

if (bev1 != null){ decimal newPrice = (decimal)bev1.UnitPrice + 10.00m; Console.WriteLine("The price of {0} is {1}. Update to {2}", bev1.ProductName, bev1.UnitPrice, newPrice);

Page 95: Curso Linq

bev1.UnitPrice = newPrice;

// submit the change to database NWEntities.SaveChanges();}

We used the ElementAtOrDefault method not the ElementAt method just in case there is no product at element 10. We know that there are 12 beverage products in the sample database, so we increase the 11th product’s price by 10.00 and call NWEntities.SaveChanges() to update the record in the database. After you run the program, if you query the database, you will find that the 11th beverage’s price is increased by 10.00.

Inserting Records

We can also create a new product and then insert this new product into the database, by using the following code:

// add a productProduct newProduct = new Product {ProductName="new test product" };NWEntities.Products.AddObject(newProduct);NWEntities.SaveChanges();Console.WriteLine("Added a new product with name 'new test product'");

Deleting Records

To delete a product, we first need to retrieve it from the database, and then call the DeleteObject method, as shown in the following code:

// delete a productIQueryable<Product> productsToDelete = from p in NWEntities.Products where p.ProductName == "new test product" select p;

if (productsToDelete.Count() > 0){ foreach (var p in productsToDelete) { NWEntities.DeleteObject(p); Console.WriteLine("Deleted product {0}", p.ProductID); } NWEntities.SaveChanges();}

Note here that we used a variable of type IQueryable<Product>, instead of IEnumerable<Product>, to hold the result of the LINQ to Entities query. Since IQueryable extends the interface IEnumerable, we can use either one of them, though with IQueryable, we can do much more as we will see in the next section.

Page 96: Curso Linq

Running the Program

The file Program.cs has been used so far. Note that we added one method to contain all of the test cases for table operations. We will add more methods later to test other LINQ to Entities functionalities. Following is the content of this file now.

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace TestLINQToEntitiesApp{ class Program { static void Main(string[] args) { // CRUD operations on tables TestTables(); Console.WriteLine("Press any key to continue ..."); Console.ReadKey(); } static void TestTables() { NorthwindEntities NWEntities = new NorthwindEntities(); // retrieve all Beverages IEnumerable<Product> beverages = from p in NWEntities.Products where p.Category.CategoryName == "Beverages" orderby p.ProductName select p; Console.WriteLine("There are {0} Beverages", beverages.Count()); // update one product Product bev1 = beverages.ElementAtOrDefault(10); if (bev1 != null) { decimal newPrice = (decimal)bev1.UnitPrice + 10.00m; Console.WriteLine("The price of {0} is {1}. Update to {2}", bev1.ProductName, bev1.UnitPrice, newPrice); bev1.UnitPrice = newPrice; } // submit the change to database NWEntities.SaveChanges(); // insert a product Product newProduct = new Product { ProductName = "new test product" }; NWEntities.Products.AddObject(newProduct); NWEntities.SaveChanges(); Console.WriteLine("Added a new product"); // delete a product IQueryable<Product> productsToDelete = from p in NWEntities.Products where p.ProductName == "new test product" select p;

Page 97: Curso Linq

if (productsToDelete.Count() > 0) { foreach (var p in productsToDelete) { NWEntities.DeleteObject(p); Console.WriteLine("Deleted product {0}", p.ProductID); } NWEntities.SaveChanges(); } NWEntities.Dispose(); } }}

If you run the program now, the output will be:

View Generated SQL Statements

You may wonder what the actual SQL statements used by LINQ to Entities to interact with the databases are. In this section, we will explain two ways to view the generated SQL statements used by LINQ to Entities queries.

There are two ways to view the generated LINQ to Entities SQL statements. The first one is to use the ObjectQuery.ToTraceString method, and the second one is to use SQL Profiler.

View SQL Statements Using ToTraceString

First let’s write a new test method to contain LINQ to SQL queries:

static void ViewGeneratedSQL(){ NorthwindEntities NWEntities = new NorthwindEntities(); IQueryable<Product> beverages = from p in NWEntities.Products where p.Category.CategoryName == "Beverages"

Page 98: Curso Linq

orderby p.ProductName select p; NWEntities.Dispose();}

As we have learned from the previous section, the variable beverages is of type IQueryable<Product>, which is a derived class of type IEnumerable<Product>. Actually, this type is also a subtype of System.Data.Objects.ObjectQuery<Product>, which has a method ToTraceString we can use to view the generated SQL statements. To make it easier for us to call the ObjectQuery.ToTraceString method, we now define an extension method like this:

public static class MyExtensions{ public static string ToTraceString<T>(this IQueryable<T> t) { string sql = ""; ObjectQuery<T> oqt = t as ObjectQuery<T>; if (oqt != null) sql = oqt.ToTraceString(); return sql; }}

Note that this extension method is inside a non-generic static class MyEntensions, and we put this class inside the namespace TestLINQToEntitiesApp, which is the same namespace of our test class, so we can use it inside our test method without worrying about importing its namespace.

Now we can print out the SQL statement of the LINQ to Entities query using this statement:

// view SQL using ToTraceString methodConsole.WriteLine("The SQL statement is:" + beverages.ToTraceString());

and we also need to add a using statement to import the namespace for the QueryObject class:

using System.Data.Objects;

The file Program.cs now should be like this:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Data.Objects;namespace TestLINQToEntitiesApp{ class Program { static void Main(string[] args) {

Page 99: Curso Linq

// CRUD operations on tables //TestTables(); ViewGeneratedSQL(); Console.WriteLine("Press any key to continue ..."); Console.ReadKey(); } static void TestTables() { // the body of this method is omitted to save space } static void ViewGeneratedSQL() { NorthwindEntities NWEntities = new NorthwindEntities(); IQueryable<Product> beverages = from p in NWEntities.Products where p.Category.CategoryName == "Beverages" orderby p.ProductName select p; // view SQL using ToTraceString method Console.WriteLine("The SQL statement is:\n" + beverages.ToTraceString()); NWEntities.Dispose(); } } public static class MyExtensions { public static string ToTraceString<T>(this IQueryable<T> t) { string sql = ""; ObjectQuery<T> oqt = t as ObjectQuery<T>; if (oqt != null) sql = oqt.ToTraceString(); return sql; } }}

Run this program, and you will see the following output:

Page 100: Curso Linq

View SQL Statements Using Profiler

With the ToTraceString method, we can view the generated SQL statements for some LINQ to Entities expressions, but not all of them. For example, when we add a new product to the database, or when we execute a Stored Procedure in the database, there is no IQueryable object for us to use to view the generated SQL statements. In this case, we can use the SQL profiler to view the SQL statements. But if you go to view the generated SQL statements for the above query, you may be confused, as there is no SQL statement displayed in SQL profiler. So we will not explain the steps to view the SQL statements in the Profiler here, but we will explain it in the next section, together with the explanation of another important LINQ to Entities feature, deferred execution.

Deferred Execution

One important thing to remember when working with LINQ to Entities is the deferred execution of LINQ.

The standard query operators differ in the timing of their execution, depending on whether they return a singleton value or a sequence of values. Those methods that return a singleton value (for example, Average and Sum) execute immediately. Methods that return a sequence defer the query execution, and return an enumerable object. These methods do not consume the target data until the query object is enumerated. This is known as deferred execution.

In the case of the methods that operate on in-memory collections, that is, those methods that extend IEnumerable<(Of <(T>)>), the returned enumerable object captures all of the arguments that were passed to the method. When that object is enumerated, the logic of the query operator is employed, and the query results are returned.

In contrast, methods that extend IQueryable<(Of <(T>)>) do not implement any querying behavior, but build an expression tree that represents the query to be performed. The query processing is handled by the source IQueryable<(Of <(T>)>) object.

Checking Deferred Execution With SQL Profiler

To test the deferred execution of LINQ to Entities, let’s first add the following method to our program.cs file:

static void TestDeferredExecution(){ NorthwindEntities NWEntities = new NorthwindEntities(); // SQL is not executed IQueryable<Product> beverages = from p in NWEntities.Products where p.Category.CategoryName == "Beverages" orderby p.ProductName select p; // SQL is executed on this statement Console.WriteLine("There are {0} Beverages",

Page 101: Curso Linq

beverages.Count()); NWEntities.Dispose();}

Call this method from the Main method of the program, and comment out the calls to the two previous test methods, then do the following:

1. Open Profiler (All Programs\Microsoft SQL Server 2005(or 2008)\Performance Tools\SQL 2005(or 2008) Profiler).

2. Start a new trace on the Northwind database engine.3. Go back to Visual Studio, set a break point on the first line of the TestDeferredExecution

method.4. Press F5 to start debugging the program.

The program is now running, and the cursor should be stopped on the first line of the method. Press F10 to move to the next line of code, and press F10 again to step over this line of code:

IQueryable<Product> beverages = from p in NWEntities.Products where p.Category.CategoryName == "Beverages" orderby p.ProductName select p;

Switch to the Profiler, you will find that there is nothing in there.

However, when you press F10 in Visual Studio and before the following statement is executed, you will see from the Profiler that a query has been executed in the database:

Console.WriteLine("There are {0} Beverages", beverages.Count());

The query executed in the database is like this:

SELECT [GroupBy1].[A1] AS [C1]FROM ( SELECT COUNT(1) AS [A1] FROM [dbo].[Products] AS [Extent1] INNER JOIN [dbo].[Categories] AS [Extent2] ON [Extent1].[CategoryID] = [Extent2].[CategoryID] WHERE N'Beverages' = [Extent2].[CategoryName]) AS [GroupBy1]

The profiler window should look as shown in the following image:

Page 102: Curso Linq

From the Profiler, we know that, under the hood, LINQ actually first creates a sub query to get the total beverage products count, then gets this count from the sub query result. It also uses an inner join to get the categories of products.

Note that with LINQ to SQL, we can set the DataContext object’s Log property to Console.Out, then view the generated SQL statements from the standard output for all subsequent LINQ to SQL expressions. Unfortunately, with LINQ to Entities, the ObjectContext does not have such a property to let us view generated SQL statements. We have to use either ToTraceString or the Profiler to view the generated SQL statements.

Deferred Execution for Singleton Methods

If the query expression will return a singleton value, the query will be executed as soon as it is defined. For example, we can add this statement to our test deferred execution method to get the average price of all products:

// SQL is executed on this statementdecimal? averagePrice = (from p in NWEntities.Products select p.UnitPrice).Average();Console.WriteLine("The average price is {0}", averagePrice);

Start SQL Profiler, then press F5 to start debugging the program. When the cursor is stopped on the line to print out the average price, from the Profiler window, we see a query has been executed to get the average price, and when the printing statement is being executed, no more query is executed in the database.

The Profiler window is like this:

Page 103: Curso Linq

Deferred Execution for Singleton Methods Within Sequence Expressions

However, just because a query is using one of the singleton methods such as sum, average, or count, this doesn't mean that the query will be executed as soon as it is defined. If the query result is a sequence, the execution will still be deferred. The following is an example of this kind of query:

// SQL is not executed even there is a singleton methodvar cheapestProductsByCategory = from p in NWEntities.Products group p by p.CategoryID into g select new { CategoryID = g.Key, CheapestProduct = (from p2 in g where p2.UnitPrice == g.Min(p3 => p3.UnitPrice) select p2).FirstOrDefault() };// SQL is executed on this statementConsole.WriteLine("Cheapest products by category:");foreach (var p in cheapestProductsByCategory){ Console.WriteLine("categery {0}: product name: {1} price: {2}", p.CategoryID, p.CheapestProduct.ProductName, p.CheapestProduct.UnitPrice);}

Start SQL Profiler, then press F5 to start debugging the program. When the cursor is stopped on the beginning of the foreach line, from the Profiler, we don’t see the query statement to get the minimum price for any product. When we press F10 again, the cursor is stopped on the variable cheapestProductsByCategory within the foreach line of code, but we still don’t see the query statement to get the cheapest products.

Page 104: Curso Linq

Then after we press F10 again, the cursor is stopped on the in keyword within the foreach line of code, and this time from the Profiler, we see the query is executed.

The actual SQL statements for this LINQ to Entities expression are like this:

SELECT 1 AS [C1], [GroupBy1].[K1] AS [CategoryID], [Limit1].[ProductID] AS [ProductID], [Limit1].[ProductName] AS [ProductName], [Limit1].[SupplierID] AS [SupplierID], [Limit1].[CategoryID] AS [CategoryID1], [Limit1].[QuantityPerUnit] AS [QuantityPerUnit], [Limit1].[UnitPrice] AS [UnitPrice], [Limit1].[UnitsInStock] AS [UnitsInStock], [Limit1].[UnitsOnOrder] AS [UnitsOnOrder], [Limit1].[ReorderLevel] AS [ReorderLevel], [Limit1].[Discontinued] AS [Discontinued]FROM (SELECT

Page 105: Curso Linq

[Extent1].[CategoryID] AS [K1], MIN([Extent1].[UnitPrice]) AS [A1] FROM [dbo].[Products] AS [Extent1] GROUP BY [Extent1].[CategoryID] ) AS [GroupBy1]OUTER APPLY (SELECT TOP (1) [Extent2].[ProductID] AS [ProductID], [Extent2].[ProductName] AS [ProductName], [Extent2].[SupplierID] AS [SupplierID], [Extent2].[CategoryID] AS [CategoryID], [Extent2].[QuantityPerUnit] AS [QuantityPerUnit], [Extent2].[UnitPrice] AS [UnitPrice], [Extent2].[UnitsInStock] AS [UnitsInStock], [Extent2].[UnitsOnOrder] AS [UnitsOnOrder], [Extent2].[ReorderLevel] AS [ReorderLevel], [Extent2].[Discontinued] AS [Discontinued] FROM [dbo].[Products] AS [Extent2] WHERE (([GroupBy1].[K1] = [Extent2].[CategoryID]) OR (([GroupBy1].[K1] IS NULL) AND ([Extent2].[CategoryID] IS NULL))) AND ([Extent2].[UnitPrice] = [GroupBy1].[A1]) ) AS [Limit1]

From this output, you can see that when the variable cheapestProductsByCategory is accessed, it first calculates the minimum price for each category. Then, for each category, it returns the first product with that price. In a real application, you probably wouldn't want to write such a complex query in your code, instead, you may want to put it in a Stored Procedure, which we will discuss in the next article.

The test method is like this:

static void TestDeferredExecution(){ NorthwindEntities NWEntities = new NorthwindEntities(); // SQL is not executed IQueryable<Product> beverages = from p in NWEntities.Products where p.Category.CategoryName == "Beverages" orderby p.ProductName select p; // SQL is executed on this statement Console.WriteLine("There are {0} Beverages", beverages.Count()); // SQL is executed on this statement decimal? averagePrice = (from p in NWEntities.Products select p.UnitPrice).Average(); Console.WriteLine("The average price is {0}", averagePrice); // SQL is not executed even there is a singleton method var cheapestProductsByCategory = from p in NWEntities.Products group p by p.CategoryID into g select new { CategoryID = g.Key, CheapestProduct = (from p2 in g where p2.UnitPrice == g.Min(p3 => p3.UnitPrice)

Page 106: Curso Linq

select p2).FirstOrDefault() }; // SQL is executed on this statement Console.WriteLine("Cheapest products by category:"); foreach (var p in cheapestProductsByCategory) { Console.WriteLine( "categery {0}: product name: {1} price: {2}", p.CategoryID, p.CheapestProduct.ProductName, p.CheapestProduct.UnitPrice); } NWEntities.Dispose();}

If you comment out all other test methods (TestTables and ViewGeneratedSQL) and run the program, you should get an output similar to the following image:

Deferred (Lazy) Loading Versus Eager Loading

In one of the above examples, we retrieved the category name of a product using this expression:

p.Category.CategoryName == "Beverages"

Even though there is no such field called categoryname in the Products table, we can still get the category name of a product because there is an association between the Products and Category tables. In the Northwind.edmx design pane, click on the line that connects the Products table and the Categories table and you will see all of the properties of the association. Note that its Referential Constraint properties are Category.CategoryID -> Product.CategoryID, meaning that category ID is the key field to link these two tables.

Because of this association, we can retrieve the category for each product, and on the other hand, we can also retrieve products for each category.

Page 107: Curso Linq

Lazy Loading by Default

However, even with an association, the associated data is not loaded when the query is executed. For example, suppose we use the following test method to retrieve all of the categories, then access the products for each category:

static void TestAssociation(){ NorthwindEntities NWEntities = new NorthwindEntities(); var categories = from c in NWEntities.Categories select c; foreach (var category in categories) { Console.WriteLine("There are {0} products in category {1}", category.Products.Count(), category.CategoryName); } NWEntities.Dispose();}

Start SQL Profiler then press F5 to start debugging the program. When the cursor is stopped on the foreach line (after you press F10 twice to move the cursor to the in keyword), from the Profiler, we see this SQL statement:

SELECT [Extent1].[CategoryID] AS [CategoryID], [Extent1].[CategoryName] AS [CategoryName], [Extent1].[Description] AS [Description], [Extent1].[Picture] AS [Picture]FROM [dbo].[Categories] AS [Extent1]

When you press F10 to execute the printout line, from the Profiler, we see this SQL statement:

exec sp_executesql N'SELECT [Extent1].[ProductID] AS [ProductID], [Extent1].[ProductName] AS [ProductName], [Extent1].[SupplierID] AS [SupplierID], [Extent1].[CategoryID] AS [CategoryID], [Extent1].[QuantityPerUnit] AS [QuantityPerUnit], [Extent1].[UnitPrice] AS [UnitPrice], [Extent1].[UnitsInStock] AS [UnitsInStock], [Extent1].[UnitsOnOrder] AS [UnitsOnOrder], [Extent1].[ReorderLevel] AS [ReorderLevel], [Extent1].[Discontinued] AS [Discontinued]FROM [dbo].[Products] AS [Extent1]WHERE [Extent1].[CategoryID] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1

From these SQL statements, we know that Entity Framework first goes to the database to query all of the categories. Then, for each category, when we need to get the total count of products, it goes to the database again to query all of the products for that category.

Page 108: Curso Linq

This is because by default lazy loading is set to true, meaning that the loading of all associated data (children) is deferred until the data is needed.

Eager Loading With Include Method

To change this behavior, we can use the Include method to tell the ObjectContext to automatically load the specified children during the initial query:

static void TestEagerLazyLoading(){ NorthwindEntities NWEntities = new NorthwindEntities(); // eager loading products of categories var categories = from c in NWEntities.Categories.Include("Products") select c; foreach (var category in categories) { Console.WriteLine("There are {0} products in category {1}", category.Products.Count(), category.CategoryName); } NWEntities.Dispose();}

As you can see, inside this test method, when constructing the LINQ to Entities query, we added an Include clause to tell the framework to load all products when loading the categories.

To test it, start SQL Profiler, then press F5 to start debugging the program. When the cursor is stopped on the foreach line (at the in keyword), from the Profiler, you will see this SQL statement:

SELECT [Project1].[CategoryID] AS [CategoryID], [Project1].[CategoryName] AS [CategoryName], [Project1].[Description] AS [Description], [Project1].[Picture] AS [Picture], [Project1].[C1] AS [C1], [Project1].[ProductID] AS [ProductID], [Project1].[ProductName] AS [ProductName], [Project1].[SupplierID] AS [SupplierID], [Project1].[CategoryID1] AS [CategoryID1], [Project1].[QuantityPerUnit] AS [QuantityPerUnit], [Project1].[UnitPrice] AS [UnitPrice], [Project1].[UnitsInStock] AS [UnitsInStock], [Project1].[UnitsOnOrder] AS [UnitsOnOrder], [Project1].[ReorderLevel] AS [ReorderLevel], [Project1].[Discontinued] AS [Discontinued]FROM ( SELECT [Extent1].[CategoryID] AS [CategoryID], [Extent1].[CategoryName] AS [CategoryName], [Extent1].[Description] AS [Description], [Extent1].[Picture] AS [Picture],

Page 109: Curso Linq

[Extent2].[ProductID] AS [ProductID], [Extent2].[ProductName] AS [ProductName], [Extent2].[SupplierID] AS [SupplierID], [Extent2].[CategoryID] AS [CategoryID1], [Extent2].[QuantityPerUnit] AS [QuantityPerUnit], [Extent2].[UnitPrice] AS [UnitPrice], [Extent2].[UnitsInStock] AS [UnitsInStock], [Extent2].[UnitsOnOrder] AS [UnitsOnOrder], [Extent2].[ReorderLevel] AS [ReorderLevel], [Extent2].[Discontinued] AS [Discontinued], CASE WHEN ([Extent2].[ProductID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] FROM [dbo].[Categories] AS [Extent1] LEFT OUTER JOIN [dbo].[Products] AS [Extent2] ON [Extent1].[CategoryID] = [Extent2].[CategoryID]) AS [Project1]ORDER BY [Project1].[CategoryID] ASC, [Project1].[C1] ASC

As you can see from this SQL statement, all products for all categories are loaded during the first query.

In addition to pre-loading one child entity, with the Include method, you can also traverse multiple child entities together. For example, you can use Include(“Products.Orders”) to preload products and orders for all categories, if Orders is also added as an Entity to the model. You can also chain multiple Includes to preload multiple child entities on the same level, like Customers.Include(“Orders”).Include(“Contacts”) if there is a Contacts table for customers, and customers, orders, and contacts are all added as entities to the model.

Note that with LINQ to SQL, you can set associations and eager loading configurations with DataLoadOptions, and you can even pre-load some objects with conditions, but with LINQ to Entities, you don’t have any other choice. You have to pre-load an entity entirely.

Another difference between LINQ to SQL and LINQ to Entities is, with LINQ to SQL you have strong typed load options for eager loading, like LoadWith<Category>, but with LINQ to Entities, you have to put the entity names within a string expression, which might cause a run time exception if you make a mistake in the entity names.

Joining Two Tables

Although associations are a kind of join in LINQ, we can also explicitly join two tables using the keyword Join, as shown in the following code:

static void TestJoin(){ NorthwindEntities NWEntities = new NorthwindEntities(); var categoryProducts = from c in NWEntities.Categories join p in NWEntities.Products on c.CategoryID equals p.CategoryID into productsByCategory select new { c.CategoryName,

Page 110: Curso Linq

productCount = productsByCategory.Count() }; foreach (var cp in categoryProducts) { Console.WriteLine("There are {0} products in category {1}", cp.productCount, cp.CategoryName); } NWEntities.Dispose();}

This is not so useful in the above example, because the tables Products and Categories are associated with a foreign key relationship. If there is no foreign key association between the two tables, or if we hadn’t added the associations between these two tables, this will be particularly useful.

From the following SQL statement, we can see that only one query is executed to get the results:

SELECT [Extent1].[CategoryID] AS [CategoryID], [Extent1].[CategoryName] AS [CategoryName], (SELECT COUNT(1) AS [A1] FROM [dbo].[Products] AS [Extent2] WHERE [Extent1].[CategoryID] = [Extent2].[CategoryID]) AS [C1]FROM [dbo].[Categories] AS [Extent1]

In addition to joining two tables, you can also:

Join three or more tables Join a table to itself Create left, right, and outer joins Join using composite keys

Querying a View

Querying a View is the same as querying a table. For example, you can query the View "current product lists" like this:

static void TestView(){ NorthwindEntities NWEntities = new NorthwindEntities(); var currentProducts = from p in NWEntities.Current_Product_Lists select p; foreach (var p in currentProducts) { Console.WriteLine("Product ID: {0} Product Name: {1}", p.ProductID, p.ProductName); } NWEntities.Dispose();

Page 111: Curso Linq

}

This will get all of the current products, using the View.

Summary

In this article, we have learned what an ORM is, why we need an ORM, and what LINQ to Entities is. We also compared LINQ to SQL with LINQ to Entities, and explored some basic features of LINQ to Entities.

The key points covered in this article include:

An ORM product can greatly ease data access layer development LINQ to Entities is one of Microsoft's ORM products that uses LINQ against a .NET

Conceptual Entity Model The built-in LINQ to Entities designer in Visual Studio 2010 can be used to model the

Conceptual Entity Model You can generate the Conceptual Entity Model from a physical database in Visual Studio

2010 Entity Model designer System.Data.Objects.ObjectContext is the main class for LINQ to Entities applications LINQ methods that return a sequence defer the query execution and you can check the

timing of the execution of a query with Profiler LINQ query expressions that return a singleton value will be executed as soon as they are

defined By default, the loading of associated data is deferred (lazy loading); you can change this

behavior with the Include method The Join operator can be used to join multiple tables and Views Views can be used to query a database in LINQ to Entities in the same way as for tables

Note

This article is based on Chapter 7 of my book "WCF 4.0 Multi-tier Services Development with LINQ to Entities" (ISBN 1849681147). This book is a hands-on guide to learn how to build SOA applications on the Microsoft platform using WCF and LINQ to Entities. It is updated for VS2010 from my previous book: WCF Multi-tier Services Development with LINQ.

With this book, you can learn how to master WCF and LINQ to Entities concepts by completing practical examples and applying them to your real-world assignments. This is the first and only book to combine WCF and LINQ to Entities in a multi-tier real-world WCF Service. It is ideal for beginners who want to learn how to build scalable, powerful, easy-to-maintain WCF Services. This book is rich with example code, clear explanations, interesting examples, and practical advice. It is a truly hands-on book for C++ and C# developers.

You don't need to have any experience in WCF or LINQ to Entities to read this book. Detailed instructions and precise screenshots will guide you through the whole process of exploring the new worlds of WCF and LINQ to Entities. This book is distinguished from

Page 112: Curso Linq

other WCF and LINQ to Entities books by that, this book focuses on how to do it, not why to do it in such a way, so you won't be overwhelmed by tons of information about WCF and LINQ to Entities. Once you have finished this book, you will be proud that you have been working with WCF and LINQ to Entities in the most straightforward way.

You can buy this book from Amazon, or from the publisher's website at https://www.packtpub.com/wcf-4-0-multi-tier-services-development-with-linq-to-entities/book.