Anda di halaman 1dari 116

Introduccin a los generics en C#

Comenzaremos hablando de los generics en el lenguaje C#, que son el mecanismo de


implementacin de clases parametrizadas.

Los generics son el mecanismo de implementacin de clases parametrizadas introducido en


la versin 2.0 del lenguaje C#. Una clase parametrizada es exactamente igual a una clase de
las habituales, salvo por un pequeo detalle: su definicin contiene algn elemento que
depende de un parmetro que debe ser especificado en el momento de la declaracin de un
objeto de dicha clase.
Esto puede resultar extremadamente til a la hora de programar clases genricas, capaces
de implementar un tipado fuerte sin necesidad de conocer a priori los tipos para los que
sern utilizadas. Confuso? Mejor lo vemos con un ejemplo.
Sabemos que un ArrayList es un magnfico contenedor de elementos y que, por suerte o por
desgracia, segn 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 ocurrira en tiempo de ejecucin, cuando muchas veces es demasiado tarde:
foreach (string s in al)
{
System.Console.WriteLine(s);
}
Efectivamente, se lanza una excepcin indicando que "No se puede convertir un objeto de
tipo 'System.Int32' al tipo 'System.String'". Lgico.
Obviamente eso se puede solucionar fcilmente, por ejemplo creando nuestra propia
coleccin partiendo de CollectionBase (o similar) y mostrar mtodos de acceso a los
elementos con tipado fuerte, o bien, usando delegacin, crear una clase de cero que

implemente interfaces como IEnumerable en cuyo interior exista una coleccin que es la
que realmente realiza el trabajo.
En cualquier caso, es un trabajazo, puesto que por cada clase que queramos contemplar
deberamos crear una clase especfica, tal y como se describe en el prrafo anterior.
Y aqu es donde los generics entran en escena. El siguiente cdigo 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 compilacin!
Con esta declaracin, no ser posible aadir a la lista objetos que no sean de la clase
indicada, ni tampoco ser necesario realizar un cast al obtener los elementos, pues sern
directamente de ese tipo.
Es interesante ver la gran cantidad de clases genricas para el tratamiento de colecciones
que se incorporaron con la versin 2.0 del framework en el espacio de nombres
System.Collections.Generic, y su amplia utilizacin a lo largo del marco de trabajo.

Creacin de clases genricas


En los ejemplos anteriores hemos visto cmo utilizar las clases genricas proporcionadas por el
framework, pero, y si queremos nosotros crear una clase genrica propia? Veremos que es muy
sencillo.

Vamos a desarrollar un ejemplo completo donde podamos ver las particularidades


sintcticas y detalles a tener en cuenta. Crearemos la clase CustodiadorDeObjetos, cuya
misin es almacenar un objeto genrico y permitirnos recuperarlo en cualquier momento.
Bsicamente, 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 definicin de la clase indicamos que sta ser una plantilla
que recibir como parmetro genrico un tipo al que hemos llamado T en el ejemplo
anterior.
Se puede apreciar cmo hemos declarado un miembro privado llamado objeto, de tipo T, al
que se puede acceder a travs del correspondiente getter y setter. El tipo concreto sobre el
que actuaremos se definir en el momento de la instanciacin de un objeto, puesto que
habr que indicarlo expresamente:
// Crea un custodiador de strings...
CustodiadorDeObjetos<string> cs = new CustodiadorDeObjetos<string>();
// Creamos un custodiador de ints
CustodiadorDeObjetos<int> ci = new CustodiadorDeObjetos<int>();
// Creamos un custodiador de Cosas
CustodiadorDeObjetos<Cosa> cp = new CustodiadorDeObjetos<Cosa>();
De esta forma, evitamos tener que crear clases especficas para cada tipo de datos con el
que necesitemos trabajar, ahorrndonos muchsimo esfuerzo y manteniendo todas las
ventajas que el tipado fuerte nos ofrece.
Y para que os hagis una idea del potencial de esta tcnica, pensad que si no existiera la
genericidad (como ocurra en versiones anteriores del lenguaje), nos veramos obligados a
implementar clases especficas 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 cdigo muestra la utilizacin de la nueva clase genrica CustodiadorDeObjetos
que definimos con anterioridad:
CustodiadorDeObjetos<string> cs = new CustodiadorDeObjetos<string>();
cs.Objeto = "Hola"; // Asignamos directamente
string s = cs.Objeto; // No hace falta un cast,
// puesto que Objeto es de tipo string
cs.Objeto = 12; // Error en compilacin,
// Objeto es de tipo string
CustodiadorDeObjetos<int> ci = new CustodiadorDeObjetos<int>();
ci.Objeto = 12; // Asignamos directamente
int i = cs.Objeto; // No hace falta un cast, pues Objeto es int
cs.Objeto = "Hola"; // Error en compilacin,
// Objeto es de tipo int

Restriccin de tipos en generics


Una particularidad interesante en la declaracin de los generics en C# es la posibilidad de establecer
limitaciones en los tipos utilizados como parmetros de las plantillas. Aunque resulte paradjico, el
propio lenguaje facilita la creacin de clases genricas que no lo sean tanto, lo cual puede resultar
realmente til en mltiples 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 genrica abierta, cuya nica operacin (Mayor(...)) permite obtener el
objeto mayor de los dos que le pasemos como parmetros. El criterio comparativo lo
pondr la propia clase sobre la que se instancie la plantilla: los enteros sern segn su valor,
las cadenas segn su orden alfabtico, etc.
A continuacin 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 despus de ellas usamos el
siguiente cdigo:
Console.WriteLine(selInt.Mayor(3, 5));
Console.WriteLine(selStr.Mayor("X", "M"));
Obtendremos por consola un 5 y una X. Todo perfecto; aparece, para cada llamada, la
conversin a cadena del objeto mayor de los dos que le hayamos enviado como parmetros.
El problema aparece cuando instanciamos la clase genrica para un tipo que no implementa
IComparable, que se utiliza en el mtodo Mayor() para determinar el objeto mayor de
ambos. En este caso, se lanza una excepcin en ejecucin 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)); // Excepcin,
// no son
// comparables!
Una posible solucin sera, antes del cast a IComparable en el mtodo Mayor(), hacer una
comprobacin de tipos y realizar la conversin slo 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 estaran intentado comparar dos objetos que no pueden ser
comparados.

La solucin ptima, como casi siempre, es controlar en tiempo de compilacin lo que


podra ser una fuente de problemas en tiempo de ejecucin. La especificacin de C#
incluye la posibilidad de definir constraints o restricciones en la declaracin de la clase
genrica, limitando los tipos con los que el generic podr ser instanciado. Y, adems, de
forma bastante simple, nada ms que aadir en la declaracin de la clase Seleccionador la
siguiente clusula where:
public class Seleccionador<T>
where T: IComparable // !Slo 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 genricos:

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 pblico sin parmetros; es
til cuando desde dentro de algn mtodo de la clase se pretende instanciar un objeto del
mismo.

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, tambin
parmetro genrico de la clase, T2.

Estas restricciones pueden combinarse, de forma que si queremos que un parmetro genrico se
cia a varias de ellas, simplemente las separamos por coma en la clusula where:

public class Seleccionador<T>


where T: IComparable, new () // Slo permitimos comparables,
// instanciable sin parmetros
Estas informaciones se completarn en el siguiente artculo en el que hablaremos de los
Mtodos genricos en C#.

Pensando en Generics
Dar el salto a los generics de .Net 2.0 supone un cambio en la forma de pensar. Como dicen
en ingls, un "mind shift". En este artculo voy a tratar de explicar los generics mediante
reglas que hagan fcil el proceso de detectar cuando se pueden usar y de qu manera. Si
bien es cierto que generics no es ya nada nuevo, an hay mucha gente que sigue con .Net
1.1. Ahora que estn trabajando en .Net 4.0, es buen momento para irse actualizando.
Me voy a basar en el cdigo 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 ms potentes puesto que el compilador de C# es ms avanzado.
Cuando vemos un cdigo que usa los smbolos "<>" como el siguiente, sabemos que se
trata de generics:
1.

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

Generics para colecciones

El uso ms claro de generics es en colecciones de elementos. Con .Net 1.1 usbamos 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 haramos lo siguiente:
1.

ArrayList myList = new ArrayList();

2.

myList.Add("this is a test");

3.

string firstItem = (string)myList[0];

En ste cdigo vemos cmo se introducen elementos en el vector y cmo 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
versin 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 continuacin, evitan el boxing-unboxing.

2. La segunda es que podemos cometer errores que slo se descubrirn en tiempo de


ejecucin. Si el lugar donde el elemento se introduce en el vector est lejos del lugar donde
se extrae, el programador podra intentar hacer el typecast a un tipo que no es el correcto. El
compilador no puede detectar ese error y es en tiempo de ejecucin cuando se producira la
excepcin.

Con generics existen clases en System.Collections.Generic que sirven para el mismo


propsito. Esta sera la alternativa al cdigo 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. Adems, 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 coleccin y estamos
haciendo un typecast, podemos darnos cuenta de que se puede reemplazar ese cdigo por
una coleccin generica.
Generics para relaciones fuertemente tipadas

Ahora vamos a ver usos ms complejos de generics, aunque en realidad cuando se adquiere
esta forma de pensar, es fcil 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 relacin entre Presenter y las instancias de IMyView es clara. Si no tuvisemos
generics el cdigo sera algo como esto:
1.

public interface IMyView

2.

3.
4.

string BackgroundColor {get; set;}


}

5.
6.

public class SomeView : IMyView

7.

8.

private string _bgcolor = String.Empty;

9.
10.

public string BackgroundColor

11.

12.

get

13.

14.

return _bgcolor;

15.

16.

set

17.

18.

_bgcolor = value;

19.
20.

}
}

21. }
22.
23. public class Presenter
24. {
25.

private IMyView _view;

26.
27.

public IMyView View

28.

29.

get

30.

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 aade algunas propiedades o funciones que no estn 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 ms fino que eso, y desde
que la jerarqua de clases crece empezamos a tener que hacer typecasts. La desventaja es la
misma que en el caso anterior, que el error slo aparece en tiempo de ejecucin. La
transformacin a generics es sencilla:
1.
2.

public class GPresenter<T>

3.
4.
5.

where T: IMyView
{
private T _view;

6.
7.

public T View

8.

9.

get

10.

11.

return _view;

12.

13.

14.
15.

public GPresenter(T view)

16.

17.

_view = view;

18.

19.

// business logic

20. }
21.
22. SomeView smView = new SomeView();
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 ejecucin, lo cual es muy valioso. La clase GPresenter hace lo mismo que Presenter,
pero su relacin con las clases que implementan IMyView es furtemente tipada, y eso le
hace ganar en eficiencia y deteccin de errores.
Forma de detectar el uso de generics: Estamos haciendo typecasts desde interfaces a
clases concretas.
Mtodos con Generics

Esto no es ms que una extensin de lo anterior. Supongamos que la clase GPresenter tiene
un mtodo que realiza determinada operacin y como resultado devuelve un objeto.
Podemos saber que el objeto ser de tipo IMyView, y escribir la firma del mtodo 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 genrico a la
definicin de la clase:
1.
2.

public class GPresenter<T, Y>

3.

where T: IMyView

4.

where Y: IMyOtherInterface

5.

Ms que llamar a los parmetros genricos, T e Y, conviene ponerles nombre, e.j, View y
LoQueSea. La sintaxis de genrics no pone restricciones a los nombres que queramos poner
a los parmetros.
Generics para envolturas (wrappers)

Cmo hacer genricas clases cuyo cdigo fuente no tenemos?. Como ejemplo os propongo
el cdigo 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 ejecucin. La
solucin es crear una nueva clase que envuelve a la que nos interesa. Dentro de dicha clase
estamos obligados a hacer typecast en algn momento, con lo que aqu no ganamos en
eficiencia, pero ganamos en deteccin de errores en tiempo de compilacin.
1.
2.

public class MyWrapper<T>

3.

4.

private TheClassWeWantToWrap _myWrap;

5.

// ...

6.

public List<T> Items

7.

8.

get

9.

10.

return (T)_myWrap.Items;

11.

12.

set

13.

14.

_myWrap.Items = value;

15.

16.

17. }

Los Generics NO son polimrficos

Una cosa que hay que tener clara es que cuando se usa un tipo genrico, 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.
3.

public class PresenterChild<T> : GPresenter<T>


where T: IMyView

4.

Por tanto en diseos de clases, normalmente la clase genrica base suele implementar una
interfaz de modo que tanto su jerarqua como las instancias que usen esa plantilla
pertenezcan a la familia de la interfaz:
1.
2.

public class MyGenericBase<T> : IMyHierarchy

3.

Vase como ejemplo ms complejo el AbstractController de DesktopRails.


La declaracin de los tipos genricos NO es recursiva pero s compleja

Algunas definiciones de clases genricas son difciles de leer, como le ocurre a


BusinessBase del framework CSLA:
1.
2.
3.

public abstract class BusinessBase<T> : BusinessBase


where T: BusinessBase<T>

4.

A primera vista parece una definicin recursiva, imposible de interpretar. Sin embargo el
compilador slo hace la sustitucin una vez y se usara as:
1.
2.

public class Customer: BusinessBase<Customer>

3.

BusinessBase es una template genrica que opera sobre un parmetro T. As algunos


mtodos devuelven como resultado un objeto de tipo T. Al imponer en la clusula "where"
que el tipo T, debe ser s mismo, lo que hacemos es eliminar el parmetro genrico 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 definicin rebuscada. El autor smplemente quera tener una clase sin
parmetros 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 parmetros


genricos. Esto es un truco que podemos recordar cuando queramos eliminar los
parmetros genricos de una clase que hereda de otra genrica.
Vamos otra clase que escrib para DesktopRails. Se trata de una relacin como en el
primer ejemplo de este artculo, en este caso entre Controller y View. Lo que pasa es que la
relacin es doble. Necesitaba que desde Controller pudiera haber una referencia a View,
pero desde View quera que tambin hubiese una relacin a Controller, porque se hacen
llamadas en ambos sentidos.
1.
2.

public interface IView<C> : IView

3.

where C : AbstractController

4.

...

5.

public abstract class AbstractController<V, C> : AbstractController

6.

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 genrico IUsersListView), solo sabe
que es de la jerarquia IUsersListView. Sin embargo, la instancia de una clase que
implemente IUsersListView s que sabe con precisin cual es el tipo exacto de Controller
que tiene asociado, es una relacin fuertemente tipada en esta direccin.
Lo que estas clusulas "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 compilacin:
1.
2.

public interface IUsersListView: IView<ControllerX>

3.

...

4.

public class UsersListController : AbstractController<IUsersListView, UsersListController>

5.

Lo anterior no compilara. Es til darse cuenta de que la asociacin que se est haciendo es
incorrecta, en tiempo de compilacin y no que falle en tiempo de ejecucin.
Regla fcil:
Cuando vemos una declaracin que parece recursiva, donde la clusula "where" del
parmetro genrico es igual a la propia declaracin, 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 declaracin 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
genricos y a uno de ellos se le dice que su relacin 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> : IUIData

3.
4.
5.

where TBaseView : IView

6.

where C : AbstractController

7.
8.

where TFinalView : TBaseView

9.

En esta definicin, se pasa el parmetro TBaseView slo para forzar que es padre de
TFinalView en la jerarqua. En verdad no se llega a usar TBaseView sino que slo se usa
para forzar una jerarqua. El sentido a esta relacin se le ve cuando vemos clases derivadas:
1.
2.

public abstract class AbstractUsersListData<T> : AbstractData<IUsersListView, UsersListController,


T>, IUsersListData

3.

where T : IUsersListView

4.

...

5.

public class TestUsersListData : AbstractUsersListData<TestUsersListView>

6.

Al ver sta ltima clase de la jerarqua puedes entender que estamos forzando a que
TestUsersListView sea una vista que implementa IUsersListView.
La verdad es que cuando estas diseando las clases, inicialmente a uno no se le ocurre
escribir estas clusulas a no se que tengas muuucha experiencia escribiendo clases iguales.
Lo que suelo hacer, al menos yo que no tengo ms materia gris que la media, es ir
modificando las clusulas segn me va haciendo falta e ir dejando que el compilador me
ayude a ver si todo va bien. Suelo pensar en trminos 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". Ms bin diseo al revs. Pienso en cmo quiero usar la clase y la voy
diseando. Al estilo TDD.
Existen ms clusulas "where" que se pueden especificar y que podeis leer en
documentacin. 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 bsico, puedes
poner esto:
1.

where T : class

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

Mtodos genricos en C#
Los mtodos genricos son interesantes herramientas que estn con nosotros desde los tiempos
del .NET Framework 2.0 y pueden resultarnos muy tiles de cara a la construccin de frameworks o
libreras reutilizables.
Podramos considerar que un mtodo genrico es a un mtodo tradicional lo que una clase genrica
a una tradicional; por tanto, se trata de un mecanismo de definicin de mtodos con tipos
parametrizados, que nos ofrece la potencia del tipado fuerte en sus parmetros y devoluciones aun
sin conocer los tipos concretos que utilizaremos al invocarlos.
Vamos a profundizar en el tema desarrollando un ejemplo, a travs del cual podremos comprender
por qu los mtodos genricos pueden sernos muy tiles para solucionar determinado tipo de
problemas, y describiremos ciertos aspectos, como las restricciones o la inferencia, que nos
ayudarn a sacarles mucho jugo.

Escenario de partida
Como sabemos, los mtodos tradicionales trabajan con parmetros 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 cdigo, vemos que el mtodo Maximo, cuya
misin 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 mximo de dos valores es una
operacin que podra ser aplicada a ms tipos, prcticamente a todos los que pudieran ser
comparados. Si quisiramos generalizar este mtodo y hacerlo accesible para otros tipos, se nos
podran ocurrir al menos dos formas de hacerlo.
La primera sera realizar un buen puado de sobrecargas del mtodo 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, sera un trabajo demasiado duro para nosotros, desarrolladores perezosos como somos.
Adems, segn Murphy, por ms sobrecargas que creramos seguro que siempre nos faltara al
menos una: justo la que vamos a necesitar ;-).

Otra posibilidad sera intentar generalizar utilizando las propiedades de la herencia. Es decir, si
asumimos que tanto los valores de entrada del mtodo como su retorno son del tipo base object,
aparentemente tendramos el tema resuelto. Lamentablemente, al finalizar nuestra implementacin
nos daramos cuenta de que no es posible hacer comparaciones entre dos object's, por lo que, o bien
incluimos en el cuerpo del mtodo cdigo para comprobar que ambos sean comparables
(consultando si implementan IComparable), o bien elevamos el listn de entrada a nuestro mtodo,
as:
public object Maximo(IComparable uno, object otro)
{
if (uno.CompareTo(otro) > 0) return uno;
return otro;
}

Pero efectivamente, como ya habris notado, esto tampoco sera una solucin vlida para nuestro
caso. En primer lugar, el hecho de que ambos parmetros sean object o IComparable no asegura en
ningn momento que sean del mismo tipo, por lo que podra invocar el mtodo envindole, por
ejemplo, un string y un int, lo que provocara un error en tiempo de ejecucin. Y aunque es cierto
que podramos incluir cdigo que comprobara que ambos tipos son compatibles, no tendrais la
sensacin de estar llevando a tiempo de ejecucin problemtica de tipado que bien podra
solucionarse en compilacin?

El mtodo genrico
Fijaos que lo que andamos buscando es simplemente alguna forma de representar en el cdigo una
idea conceptualmente tan sencilla como: "mi mtodo 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 mtodos genricos 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 cdigo anterior, podemos distinguir el parmetro genrico T encerrado entre ngulos "<" y
">", justo despus del nombre del mtodo y antes de comenzar a describir los parmetros. Es la
forma de indicar que Maximo es genrico y operar sobre un tipo cualquiera al que llamaremos T; lo
de usar esta letra es pura convencin, podramos llamarlo de cualquier forma (por ejemplo MiTipo
Maximo<MiTipo>(MiTipo uno, MiTipo otro)), aunque ceirse a las convenciones de codificacin es
normalmente una buena idea.
A continuacin, podemos observar que los dos parmetros de entrada son del tipo T, as como el
retorno de la funcin. Si no lo ves claro, sustituye mentalmente la letra T por int (por ejemplo) y
seguro que mejora la cosa.

Lgicamente, estos mtodos pueden presentar un nmero indeterminado de parmetros genricos,


como en el siguiente ejemplo:
public TResult MiMetodo<T1, T2, TResult>(T1 param1, T2 param2)
{
// ... cuerpo del mtodo
}

Restricciones en parmetros genricos


Retomemos un momento el cdigo de nuestro mtodo genrico 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 porcin final de la firma del mtodo anterior, donde encontramos el
cdigo where T: IComparable. Se trata de una restriccin 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 comparacin.
Existen varios tipos de restricciones que podemos utilizar para limitar los tipos permitidos para
nuestros mtodos 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 pblico sin parmetros; es

til cuando desde dentro del mtodo 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, tambin

argumento del mtodo, T2.


Un ltimo detalle relativo a esto: a un mismo parmetro se pueden aplicar varias restricciones, en
cuyo caso se separarn 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 mtodo
}

En cualquier caso, las restricciones no son obligatorias. De hecho, slo debemos utilizarlas cuando
necesitemos restringir los tipos permitidos como parmetros genricos, como en el ejemplo del
mtodo Maximo<T>, donde es la nica forma que tenemos de asegurarnos que las instancias que nos
lleguen en los parmetros puedan ser comparables.

Uso de mtodos genricos


A estas alturas ya sabemos, ms o menos, cmo se define un mtodo genrico, pero nos falta an
conocer cmo podemos consumirlos, es decir, invocarlos desde nuestras aplicaciones. Aunque
puede intuirse, la llamada a los mtodos genricos debe incluir tanto la tradicional lista de
parmetros del mtodo como los tipos que lo concretan. Vemos unos ejemplos:
string mazinger = Maximo<string>("Mazinger", "Afrodita");
int i99 = Maximo<int>(2, 99);

Una interesantsima caracterstica de la invocacin de estos mtodos es la capacidad del compilador


para inferir, en muchos casos, los tipos que debe utilizar como parmetros genricos, evitndonos
tener que indicarlos de forma expresa. El siguiente cdigo, totalmente equivalente al anterior,
aprovecha esta caracterstica:
string mazinger = Maximo("Mazinger", "Afrodita");
int i99 = Maximo(2, 99);

El compilador deduce el tipo del mtodo genrico a partir de los que estamos utilizando en la lista
de parmetros. Por ejemplo, en el primer caso, dado que los dos parmetros son string, puede llegar
a la conclusin de que el mtodo tiene una signatura equivalente a string Maximo(string, string), que
coincide con la definicin del genrico.

Otro ejemplo de mtodo genrico


Veamos un ejemplo un poco ms complejo. El mtodo CreaLista, aplicable a cualquier clase, retorna
una lista genrica (List<T>) del tipo parametrizado del mtodo, 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 beneficindonos 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 annimos de C# 3.0:
var p = CreaLista(
new { X = 1, Y = 2 },
new { X = 3, Y = 4 }
);
Console.WriteLine(p[1].Y); // Pinta "4"

En resumen, se trata de una caracterstica 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.

Inferencia de Tipos: Cmo funciona?

Si hay algo que veo que cuesta que los desarrolladores entiendan o mejor dicho confen es
en la inferencia de tipos que presenta .net Framework 3.5. Muchos creen que al usar la
palabra var, estn resucitando al costoso tipo Variant de Visual Basic 6.0 o creen que estn
declarando una variable del tipo Object y que en tiempo de ejecucin se resuelve el tipo al
que pertenece dicha variable como los hacen los lenguajes dinmicos.
Afortunadamente no es as, la resolucin del tipo al que pertenece una variable se resuelve
en tiempo de compilacin no en tiempo de ejecucin. 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 declaracin explcita de su tipo. El tipo es
inferido a partir del valor inicial provisto a la variable. A continuacin 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 compilacin.

La ejecucin nos revela que el compilador ha inferido que el contenido de inferredType


es del tipo System.Int32.

Este resultado sera el mismo que obtendramos si hubiramos escrito el siguiente cdigo:

La mejor forma de verificar esto es analizando el IL que generan ambas implementaciones


tanto la inferida como la explcita. Con la ayuda de Reflector el cdigo fuente en C# que se
obtiene de analizar el IL de ambos ejecutables es exactamente el mismo.

Ahora bien, analicemos esta situacin de error:

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
conversin de tipos. Me parece importante destacar esta situacin 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 ms adecuado para la misma. Pues les tengo malas
noticias, el algoritmo de inferencia funciona a partir de la primera evaluacin eventual de una
expresin, y esto est bien que sea as ya que la funcin del compilador es resolver el tipo mediante
la reduccin de expresiones al tipo atmico ms implcito que le permita compilar. En el caso de
este ejemplo la expresin analizar es una constante numrica. Si se analizaran todas las expresiones
en las que interviene una variable para posteriormente generalizar al mejor tipo, el compilador
necesitara una instancia privada de SQL Server Analisys Services y tardara 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 cdigo es el siguiente:

Al ejecutarlo obtenemos:

Y cuando analizamos el IL con reflector, conseguimos:

La inferencia en los tipos por valor generaliza al tipo ms implcito y optimizado del .net
Framework. Como el Framework optimiza la performance para tipos enteros de 32bit(System.Int32 y System.UInt32) un valor de 0,10 100 que perfectamente podra
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 ejecucin 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 razn es que las operaciones
con System.Double son optimizadas por hardware. Slo 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.

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 explcito
var inferredType = 3.14f; // notacin sufijo

Entonces, resumiento:

La inferencia de tipos no es una solucin automgica, el compilador no es psquico


ni el tipo de la variable se resuelve utilizando mecanismos de cdigo dinmico, que
afecten la performance en tiempo de ejecucin.

La inferencia de tipos se resuelve en tiempo de compilacin, por lo tanto existe un


costo en tiempo de compilacin, ese costo es el tiempo que tarda el algoritmo de
inferencia en sintetizar una expresin y resolver el tipo de una variable.

La inferencia de tipos tanto de valor como de referencia es para variables locales de


mtodos. No se aplica para variables de clase, propiedades, parmetros ni valores de
retorno.

La inferencia de tipos no es nada ms que azcar sintctica. 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 tecnologa legacy as que actualcense a
Visual Basic.net

Tipos annimos en C#.NET

Que es?
Antes de nada, tipos annimos no es lo mismo que inferencia de datos.
Los tipos annimos difieren de la inferencia de datos. La inferencia se usa para crear tipos
de objetos ya existentes, y los tipos annimos, para crear objetos recortados, los creas al
vuelo.
Me explico, lo que puedes crear con los tipos annimos 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 cdigo, hemos creado un objeto con las propiedades de nombre(String),
apellido(String),diaNacimiento(Integer). Lo que hace internamente es lo siguiente:
El objeto se declarara as (internamente):
class f__AnonymousType0<T0, T1, T2>{
public T0 nombre;
public T1 apellido;
public T2 diaNacimiento;
}

Y la declaracin sera (internamente):


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

Para comparar los objetos annimos, comprobara el contenido de las propiedades, se puede
usar Equals o == , la diferencia es que Equals comprueba tambin el tipo.
Annimos con Arrays
Por supuesto, una propiedad puede interesarnos que una propiedad sea un array, este
ejemplo son de un listado de lenguajes de programacin y otro parmetro, que es el da de
nacimiento:
var persona = new
{
nombre="for",
apellido="Code",
lenguajes= new[]{
new {nombre="Php"},
new {nombre=".Net"},

new {nombre="java"}
},
diaNacimiento=9
};

Annimos con colecciones


Por supuesto, una propiedad puede interesarnos que una propiedad sea una coleccin, este
ejemplo son de un listado de lenguajes de programacin:
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!

Inicializadores de objeto y de coleccin

Los inicializadores de objeto permiten asignar valores a los campos o propiedades


accesibles de un objeto en el momento de la creacin sin tener que invocar explcitamente
un constructor. En el ejemplo siguiente se muestra cmo 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 ms informacin, vea Propiedades autoimplementadas (Gua de
programacin 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 annimos


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 annimos, que solo se pueden inicializar con un inicializador de
objeto, como se muestra en la siguiente declaracin.
var pet = new { Age = 10, Name = "Fluffy" };

Los tipos annimos habilitan la clusula select de una expresin 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
informacin de cada objeto de una secuencia. En el ejemplo siguiente se supone que un
objeto de producto (p) contiene muchos campos y mtodos, y el usuario slo 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

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 instruccin foreach, como se muestra en este ejemplo:
foreach(var p in productInfos){...}

Cada objeto del nuevo tipo annimo tiene dos propiedades pblicas que reciben los mismos
nombres que las propiedades o campos del objeto original. Tambin puede cambiar el
nombre de un campo al crear un tipo annimo; 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 compilacin para utilizar un inicializador de objeto con un struct
que acepta valores NULL.

Inicializadores de coleccin
Los inicializadores de coleccin permiten especificar uno o ms inicializadores de elemento
cuando se inicializa una clase de coleccin que implementa IEnumerable. Los
inicializadores de elemento pueden ser un valor simple, una expresin o un inicializador de
objeto. Si se utiliza un inicializador de coleccin, no es necesario especificar varias
llamadas al mtodo Add de la clase en el cdigo fuente; el compilador agrega las llamadas.
En los ejemplos siguientes se muestran dos inicializadores de coleccin 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 coleccin 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 },
new Cat(){ Name = "Whiskers", Age=2 },
new Cat(){ Name = "Sasha", Age=14 }
};

Puede especificar null como elemento de un inicializador de coleccin si el mtodo Add de


la coleccin 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
};
// 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.
}

Mtodos de extensin en C#

Los mtodos de extensin permiten agregar mtodos 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 mtodos de extensin constituyen un tipo especial de mtodo
esttico, pero se les llama como si se tratasen de mtodos de instancia en el tipo extendido.
En el caso del cdigo de cliente escrito en C# y Visual Basic, no existe ninguna diferencia
aparente entre llamar a un mtodo de extensin y llamar a los mtodos realmente definidos
en un tipo. MSDN
Ciertamente esta es una descripcin bastante criptica de esta tcnica de desarrollo que se
puede utilizar para una mayor productividad y legibilidad de nuestro cdigo. Por ello quiero
escribir un artculo que, por medio de un ejemplo muy sencillo, pueda ser un paso inicial en
el conocimiento de esta herramienta de programacin.
Bsicamente, y para entendernos de una forma ms sencilla. Un mtodo extensor es una
forma de aadirle mtodos a una clase sin necesidad de hacerlo en la original o en alguna
instancia/copia de la misma. No es un reemplazo de la tcnica formal por medio de
herencia, si no una pequea trampa que nos permite obtener un resultado muy similar.

Preparando el proyecto

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#
podra tambin utilizar el Visual Studio Express 11.
Para este artculo me creo un nuevo proyecto Web, de tipo MVC4 (que tambin es beta)
vaco. He elegido este tipo para no tener ningn 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 continuacin aado una pgina de clases en la carpeta de Modelo, llamada
Comprobaciones, en donde voy a insertar una clase que realice diversas comprobaciones
bsicas y en donde voy a definir mtodos extensores que me haga el cdigo ms legible.
El primer paso de mi ejemplo es enunciarlo. Describir la visin 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 aos. 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 mtodo de entrada que
se llamar esCorrecto, recibiendo como parmetro un objeto del tipo Persona. Como vers, la
primera validacin 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 cdigo refactorizando con mtodos extensores y creemos un
nuevo mtodo para la clase Persona. Esto se hace de forma muy sencilla creando una nueva clase
esttica llamada extensores en donde voy a dar de alta un mtodo tambin esttico que tiene la
particularidad de extender la clase Persona de la siguiente forma.

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 mtodo 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
aplicacin en donde tendr muchos ms objetos a los que hacer la misma comprobacin. O sea que
con muy poco esfuerzo puedo extender el propio tipo object y as TODOS mis objetos sern
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 mtodo 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();
}
}

Pero vamos a darle una pequea vuelta de tuerca extendiendo otra vez a la clase Persona para
realizar la comprobacin de que tiene un nombre vlido. Como todos sabemos, en la ltima versin
del framework de .NET podemos hacer dos comprobaciones diferenciadas que nos digan si la
cadena de texto es nula, esta vaca o es un espacio en blanco. Por lo cual si quiero comprobar si
el nombre es vlido 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 mtodo 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 cdigo aumenta mucho y adems tengo encapsulado en un solo sitio la
lgica de comprobacin del campo. Es ms, as cumplo a rajatabla el concepto de que mi mtodo
no debe saber cmo 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 tcnica podemos obtener un cdigo ms legible y mantenible. Pero no es todo oro lo
que reluce y hay que tener los inconvenientes inherentes a esta tcnica.

Primero el cdigo es dependiente del intellisense del Visual Studio, ya que desde el fichero
fuente abierto no puedes saber si el mtodo invocado es parte de la instancia o es un
mtodo extensor. Lo cual puede causar dolores de cabeza para localizar el cdigo si no
ests con el IDE adecuado.
Otro problema es que el ciclo de vida de la clase y de los mtodos 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 aade un mtodo de
instancia con el mismo nombre que el mtodo extensor, este dejar de funcionar ya que el
compilador utilizar antes el mtodo de instancia que el extensor. Lo cual es un error muy
difcil de localizar.
A causa de ello, se aconseja darle prioridad al uso de los mtodos de instancia y a la
herencia, antes que a los mtodos extensores. Lo cual no quita que herramientas como
Linq est construida en su totalidad con esta tcnica de desarrollo.

Ahora solo queda, probar y practicar, para tener un conocimiento en ms profundidad que
te permita tomar las decisiones ms 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);
}
}
}

03/05/2012 He aadido un enlace a una biblioteca de mtodos extensores que ser de gran
utilidad.

Delegados en C#
Introduccin

Uno de los temas que ms 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 travs 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
definicin seria:
Los delegados son un tipo que representa a una funcin con una determinada
declaracin.

Vamos a analizar esta definicin poco a poco, ya que dice mucho en muy pocas palabras...

Los delegados son un TIPO.

Los delegados representan a una funcin.

La funcin debe tener una determinada declaracin.

Si un delegado es un tipo, entonces puedo crear variables de ese tipo. Tambin hemos dicho
que un delegado representa a una funcin, por lo que una variable creada de un tipo
delegado es la representacin de una determinada funcin. Por litmo hemos dicho que esta
funcin debe tener una determinada declaracin.
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 funcin que devuelve un entero y que recibe como argumento tambin 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 excepcin. Para
asignar un delegado, no debemos asignar un "valor", sino un mtodo, normalmente una
funcion. El mtodo al que asignemos el delegado no puede ser una funcin cualquiera, debe
cumplir con la declaracin del delegado. La forma de asignarlo es a travs del constructor
del delegado, pasando como argumento la funcin.
A continuacion mostramos dos posibles funciones que cumplen con la declaracin 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 declaracin 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
pequeo 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);
}
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 funcin


delegateFunction1. Debido a que el mtodo Main es esttico, pero delegateFunction1 no
lo es, necesitamos una instancia de la clase MainClass para referiros a la funcin de forma
concreta. Por litmo ejecutamos nuestra variable (con un parmetro fijo 5) y mostramos el
resultado en pantalla.
El programa genera una salida similar a la siguiente:

Ejecutando ... delegateFuntion1


El resultado obtenido es ... 6
Presione una tecla para continuar . . .

Seguro que alguno de vosotros est pensando en que esto mismo podra hacerse invocando
a la funcion sin ms, y no andar con tanto lo. 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 ms complejo podra 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 funcin 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 declaracin del delegado.
Vamos ahora a ver un ejemplo algo ms prctico.

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.
El programa tiene tres clases:

MainClass, que es la clase que contiene el mtodo 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 adems 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
mtodos (que coinciden con la declaracin 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 cdigo 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 mtodos y miembros:

logFunction, que es un miembro de tipo logDelegate y es la funcin encargada de


realizar el log

Run, que es el mtodo principal de la clase, unicamente comprueba que


logFunction est asignada e itera 100 veces llamando al mtodo Log.

SetLogMethod, este mtodo es el ms importante de todos, ya que recibe un


parmetro de tipo logDelegate y lo asigna a logFunction para que pueda hacer su
trabajo de forma correcta.

Log, este mtodo ejecuta logFunction.

El cdigo 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 mtodo Main en el
que se inicia la ejecucin del programa.
El mtodo 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 seleccin del usuario llama al mtodo SetLogMethod del objeto
"programa" pasandole una nueva variable de tipo logDelegate construida con las
funciones que proporciona la clase FormasLog.
El cdigo de la clase es:
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 ningn 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. Podramos escribir una nueva funcion y decirle al componente que la utilice, solo
tendramos que llamar al metodo SetLogMethod.
El cdigo completo del programa se muestra a continuacin:

namespace Devjoker.Ejemplos
{
delegate void logDelegate(string arg) ;
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 ( );
}
}
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)
{
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.

Mtodos annimos

Estoy seguro que usted recordar su primera clase de programacin donde le ensearon la
manera de crear mtodos e invocarlos. Pues bien, estos mtodos que usted aprendi tienen
una sintaxis que hacen prosible la invocacin como la especificacin de ciertos parmetros
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 mtodo llamado miMetodo seguido
de un parmetro entero para este. La manera de invocarlo usando un delegado es muy fcil,
y eso lo sabe usted bien. Bueno, as como existe este mtodo con nombre, tambin existe
los recien conocidos Mtodos Annimos, que viene con C# 2.0 como parte de una de sus
novedades de programacin. Pues usted se preguntar y que s un mtodo annimo? Un
mtodo annimo es justamente eso, aquel mtodo que no tiene un nombre especfico. Y
ahora usted se preguntar y cmo invoco los mtodo annimos?, pues buena pregunta, la
respuesta es usando Delegados.
El detalle es que siempre hemos estado acostumbrados a nombrar las mtodos, tanto
aquellos que devuelven valores nulos o los que devuelven un cierto valor para su posterior
uso, y esta novedad de Mtodos annimos en C# 2.0, viene a ser el tema de este post. Es
por eso que paso a explicar lo concerniente a Mtodos Annimos usando Delegados.
Lo importante es que los mtodos annimos, reduce la sobrecarga de codificacin al crear
instancias de delegados sin tener que crear un mtodo independiente. Un mtodo annimo
es declarado con la palabra clave delegate seguido de una lista de parmetros. Las lneas de
cdigo para el mtodo estn dentro del par de llaves {}. Todo esto debe ser referenciado por
un tipo delegate que tenga la misma firma que el mtodo annimo, es as que, la invocacin
de los mtodos annimos 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 funcin, debemos instanciar el delegado correspondiente e invocarlo.


Static void Main(string[] args)
{
//referenciamos un delegate de tipo arriba definido.
toString ts;
//declaramos un mtodo annimo usando delegado.
ts = delegate(Boolean b) { Console.WriteLine("\ntoString: {0}", b == true ? "Verdadero: "Falso");};

ts(true); //invocacin del mtodo annimo usando delegado.


}

De esta manera explotaremos la nueva funcionalidad de los mtodos annimos. Para


entender mejor aqu algunos ejemplos ms. He aqu otra demostracin. Ya sabis lo que se
hace primero:
delegate void printIntView(int valor);

Ahora se deben instanciar los delegados y los mtodos annimos. Esto es explicado dentro
de las siguientes lneas de cdigo.
static void Main(string[] args)
{
//creamos los delegados a partir de tipo definido printIntView
printIntView entero, hexa, oChar, EHC,HC, EC;
//otros mtodos annimos
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);//invocacin
HC= EHC - entero;
Console.Write("\nHC: ");
HC(128);//invocacin
EC = EHC - hexa;
Console.Write("\nEC: ");
HC(128); //invocacin
Console.ReadLine();
}

Ya sabis esto de los mtodos annimos, y espero que nuevamente este post sea de utilidad.

C#: Desmitificando las expresiones lambda


(I)
Entre las mltiples 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 ms complejas, probablemente por su relacin con
conceptos no demasiado asimilables como los delegados, inferencia de tipado, mtodos annimos, o
tipos genricos, entre otros.
Sin embargo, esa aparente dificultad desaparece en cuanto se les presta un poco de atencin, y una
vez comprendidas aportan a los desarrolladores una potencia y agilidad difciles de lograr con las
herramientas disponibles hasta el momento. Slo hay que ver su amplia utilizacin dentro del
propio .NET framework, LINQ, y nuevas plataformas como ASP.NET MVC, para darse cuenta de
su importancia. Y por si fuera poco, segn 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 prctico, con la nica pretensin de aportar algo de luz a los que todava no han sucumbido a
su poder. ;-)
El objetivo de este primer post es puramente introductorio, y tratar conceptos y nociones bsicas
para poder abordar los siguientes. En el segundo post de la serie trataremos las expresiones lambda
como funciones annimas, dejando para el tercero los misteriosos rboles de expresin.

Introduccin a las lambda


Segn la definicin en la Referencia del lenguaje C# de MSDN:
"Una expresin lambda es una funcin annima que puede contener expresiones e instrucciones y
se puede utilizar para crear delegados o tipos de rboles de expresin"
En la Gua de programacin de Visual Basic 9 encontramos otra definicin, muy simple y
pragmtica:
"Una expresin lambda es una funcin sin nombre que calcula y devuelve un solo valor. Se pueden
utilizar las expresiones lambda dondequiera que un tipo de delegado sea vlido"
ScottGu tambin aport su granito de arena para hacer el concepto ms cercano a los
desarrolladores; como siempre, al grano:
"Las Expresiones Lambda aportan una sintaxis ms concisa y funcional para escribir mtodos
annimos."
[...]
"La forma ms sencilla para conceptualizar las expresiones lambda es pensar en ellas como formas
de escribir mtodos breves en una lnea."

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 parmetros que se les suministra, aunque en determinados casos es posible que no reciba
ningn parmetro, o que realicen una accin sin retornar nada. Igual que una funcin tradicional,
vaya. Y de hecho, en el cuerpo de una expresin lambda puede haber casi de todo: llamadas a otras
funciones, expresiones, bucles, declaraciones de variables...
Sin embargo, a diferencia de los mtodos 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 parmetro de una funcin, pasando el destinatario de esta asignacin a
actuar como delegado, o puntero, hacia la misma, o a ser el contenedor del rbol de expresin que la
representa. Ein? Chino, eh? No pasa nada, dentro de poco estudiaremos estos dos usos en
profundidad, pero antes vamos a ver cmo se definen las expresiones lambda a nivel de cdigo.

Forma de las expresiones lambda


Las expresiones lambda en C# se escriben segn el patrn descrito a continuacin, al que le siguen
algunos ejemplos que lo ilustran e introducen algunas particularidades.
Forma general: parmetros => expresin, donde:
- parmetros: lista de parmetros separados por comas
- "=>: separador.
- expresin: implementacin de las operaciones a realizar
num => num * 2

// Lambda con un parmetro que retorna


// el doble del valor que se le pasa.

(a, b) => a + b

// Lambda con dos parmetros que retorna


// la suma de ambos.

num => {
int x = new Random().Next();
return num+x;
}

// Lambda con cuerpo que recibe un


// entero, y retorna la suma de ste
// con un nmero aleatorio.

() => DateTime.Now // Lambda que no recibe parmetros


// y retorna la fecha y hora del sistema.
msg => Console.WriteLine(msg); // Recibe un parmetro, realiza una
// accin y no retorna nada.

Como se puede observar, cuando slo existe un parmetro no es necesario utilizar parntesis en el
lado izquierdo de la expresin, mientras que hay que hacerlo en todos los dems casos. Tambin 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 parmetros ni el retorno de la funcin tienen indicado un tipo.
Aunque puede hacerse, normalmente no ser necesario puesto que el compilador podr inferir

(deducir) el tipo a partir de su contexto, ms adelante veremos cmo es esto posible. Por tanto, no
es necesario escribir cdigo 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 annimas y facilitadoras del trabajo con delegados.

C#: Desmitificando las expresiones lambda


(II)
En el post anterior intentamos realizar una primera aproximacin a las expresiones lambda,
centrndonos en obtener una definicin lo suficientemente cercana, que nos permitiera conocer a
grandes rasgos qu son, as como en describir su forma general y sus particularidades sintcticas.
En esta segunda entrega vamos a profundizar un poco en el papel de las expresiones lambda como
va para definir muy rpidamente funciones annimas 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
generacin de rboles de expresin.

Las lambdas como funciones annimas


Como habamos insinuado anteriormente, uno de los usos de las expresiones lambda es permitir la
definicin "en lnea" de funciones annimas. De hecho, en tiempo de compilacin las expresiones
lambda son convertidas en mtodos a los que el compilador establece un nombre nico
autogenerado, como los ejemplos mostrados a continuacin:

Las referencias a estas funciones annimas son transformadas en delegados (punteros) a las mismas,
lo que nos permitir, por ejemplo, invocarlas desde el cdigo. En la prctica esto quiere decir que
podemos asignar una lambda a una variable y ejecutarla como muestra el siguiente pseudocdigo:
delegado duplica = x => x * 2;
escribe duplica(2); // Escribe un 4

En este primer acercamiento, fijaos que duplica es el nombre del delegado, la funcin definida en
forma de expresin lambda no tiene nombre, ser el compilador el que se asigne uno.

Veamos cmo se concreta esta idea en C#. En el siguiente cdigo, la variable duplica apunta hacia
una funcin annima definida a travs de la expresin lambda en cuya implementacin lo nico que
se hace es retornar el doble del valor que le llega como parmetro. Vemos tambin cmo podemos
utilizarla de forma directa:
Func<int, int> duplica = x => x * 2;
int result = duplica(7); // result vale 14
Slo con objeto de que podis entender el cdigo anterior, os adelantar que la porcin Func<int, int>
es una forma rpida de tipificar el delegado, indicando que duplica apunta a una funcin que espera
un entero como parmetro 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 expresin lambda a una variable, podemos hacerlo tambin
para indicar el valor de un parmetro a un mtodo que acepte un delegado concreto. Por ejemplo, el
siguiente cdigo muestra un mtodo llamado calcula que recibe un valor entero y una referencia a
una funcin, retornando el resultado de efectuar dicha operacin sobre el entero proporcionado:
// Es mtodo ejecuta la funcin indicada por
// el parmetro operacion, envindole 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 expresin indicada al valor.
}
// Usos posibles:
int i = calcula(4, x => x / 2);

int j = calcula(4, duplica);

// Le pasamos una referencia a la


// funcin que estamos definiendo sobre
// la marcha. El resultado es que i=2.
// Le pasamos la variable "duplica",
// que es una referencia a la lambda
// definida anteriormente. J valdr 8.

<HistoriaDelAbuelete>
Seguro que a los ms viejos del lugar esto le recuerda a los Codeblocks que utilizbamos en Clipper
a principios de los 90 (uuf, cmo pasa el tiempo...). Todava reconocis el siguiente cdigo?
bDuplica := { |n| n*2 }
? EVAL(bDuplica, 7) // Muestra un 14

</HistoriaDelAbuelete>
Una consecuencia directa de que las expresiones lambdas sean referenciadas a travs de delegados
es que podemos utilizarlas en cualquier sitio donde se acepte un delegado, con la nica
precaucin de escribirla teniendo en cuenta el tipo de su retorno y los parmetros que recibe. Un
ejemplo claro lo tenemos en la suscripcin a eventos, donde la tcnica habitual consiste en utilizar

un delegado a un mtodo en el que se implementa la lgica del tratamiento de los mismos, algo
como:
// 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 aadindole delegados del tipo
MouseEventHandler, definido en System.Windows.Forms, cuya firma indica que recibe un parmetro
de tipo object, otro de tipo MouseEventArgs y no retorna ningn valor, exactamente igual que sera un
delegado annimo (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 cdigo ms compacto:
this.MouseMove += (sender, args) => {
this.Text = args.X + "," + args.Y;
};

Llegados a este punto es conveniente aclarar que las expresiones lambda son caractersticas
introducidas en los lenguajes, y por tanto en sus compiladores, pero no en la plataforma de
ejecucin (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 ms tediosa, utilizando
mecanismos que la versin 2.0 del framework pona a nuestra disposicin, como los delegados y
mtodos annimos. En este sentido, el uso de expresiones lambda aportan mucha simplicidad,
elegancia y legibilidad al cdigo.
Esto explica, adems, que Visual Studio 2008 sea capaz de generar cdigo para .NET 2.0 a partir de
cdigo fuente C# 3.0.

Tipos de delegados de expresiones lambda


Antes ya haba adelantado que la definicin Func<int, int> era simplemente una forma de indicar el
tipo del parmetro que reciba la funcin lambda, as como el tipo del valor de retorno. En realidad,
lo nico que estbamos haciendo era definir, de forma muy sencilla y rpida, el delegado hacia la
funcin.
Vamos a concretar esto un poco ms, pero antes de continuar, una cosa: si para t un genrico 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 introduccin a los generics en c#, o
la Gua de programacin de C#.
.NET Framework ofrece en el espacio de nombres System un conjunto de definiciones de genricas
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, estn destinados a referenciar a
lambdas que realicen acciones y que no retornen ningn valor. De ah su nombre tambin. ;-)
Una de estas definiciones es la que habamos usado en un ejemplo anterior:
Func<int, int> duplica = x => x * 2;
Como se puede observar, al tratarse de una referencia a una funcin que retorna un valor, hemos
utilizado un tipo Func con dos parmetros genricos, que corresponde con la siguiente declaracin
existente en el espacio de nombres System:
Public delegate TResult Func<T, TResult>(T arg);
Por ello, cuando declarbamos que la variable duplica era del tipo Func<int, int>, lo que indicbamos
era, en primer lugar que el parmetro que necesitaba la lambda era un int, y que sta nos devolvera
tambin un int, es decir, lo mismo que si hubiramos definido duplica as, utilizando mtodos
annimos de C# 2.0:
// En el rea de declaraciones:
public delegate int Duplicador(int arg);
...
// En el cdigo:
Duplicador duplica = delegate(int k) {return k*2 };

Obviamente, la sintaxis lambda es mucho ms compacta y expresiva.


En la prctica, lo nico que tenemos que tener claro a la hora de referenciar una funcin lambda es
el tipo de cada uno de los parmetros que usa, y el tipo de retorno. Estos se introducen, en ese
orden, en los parmetros genricos de la clase Func y listo. Como esto debe quedar claro, ah van
unos ejemplos de definicin 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"

Es importante saber que en el framework estn definidos los delegados Func<tipo1, tipo2...,
tipoResult> para funciones de hasta cuatro parmetros. Si necesitamos ms deberemos definir los
delegados a mano, aunque esto es realmente sencillo utilizando una de las declaraciones existentes
y aadindole el nmero de parmetros que deseemos. Por ejemplo, para seis parmetros la
definicin del genrico sera 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 pequeo problema: las funciones sin retorno no pueden referenciarse con
delegados de tipo Func, puesto que el framework .NET no soporta la instanciacin de tipos
genricos utilizando parmetros void (ECMA 335, seccin 9.4, pg. 153). Por tanto, no podramos
declarar un delegado como Func<int, void> para apuntar hacia una funcin que recibe un entero y no
devuelve nada. Si lo pensis un poco, este es el motivo de que no exista ninguna sobrecarga de la
clase Func sin parmetros genricos, pues como mnimo debemos indicar el tipo del valor de
retorno.
La clave para cubrir estos casos se encuentra en el tipo Action. Como comentaba unas lneas ms
arriba, el objeto de estos tipos de delegados es apuntar a expresiones lambda que realicen acciones y
que no retornen ningn valor, por lo que sus parmetros genricos describirn exclusivamente los
tipos de los parmetros de la funcin. En este caso, como es obvio, s existe una clase no
parametrizada Action para apuntar a funciones sin parmetros, adems de disponer de genricos que
cubren las acciones de hasta cuatro parmetros. Veamos unos ejemplos:
// Accin sin parmetros (no genrica):
Action saluda = () => Console.WriteLine("hola");
saluda(); // Muestra "hola";
// Accin que recibe un string
Action<string> apaga = motivo => {
log(motivo);
shutdown();
};
apaga("mantenimiento"); // Apaga el sistema

Por ltimo, me parece interesante recordar algo que haba comentado en el post anterior, que en las
expresiones lambda no era necesario indicar el tipo de los parmetros ni del retorno porque el
compilador los infera del contexto. Como podemos ver, lo tiene bastante fcil, puesto que
simplemente debe tomar la definicin 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 ms cmoda:

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

En cualquier caso, si por algn motivo es necesario utilizar la forma explcita, sabed que no se
permite hacerlo de forma parcial, es decir, o le ponis los tipos a todo, o no se los ponis a nada.

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, Ill
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 delegates 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!");
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.

Weve got the Func delegates


Just like its 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.
For example, lets 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);
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 its 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.

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).

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).

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).

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();
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 well 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:
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.
Wed still want to unit test our code to make sure the logic is accurate, but we dont 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: }
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.
Stay tuned in the weeks that follow for other generic delegates in the .NET Framework!
Crear peticiones LINQ

1. Presentacin
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:

Utilizacin 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 peticin LINQ To Objects


Una peticin Linq se compone de clusulas, y cada una de ellas tiene una funcin definida.
A continuacin se muestran algunas de estas clusulas:

From : permite declarar los objetos utilizados en la peticin.

In : permite especificar los conjuntos de objetos fuente.

Where : permite filtrar los objetos que se devolvern.

Orderby : permite ordenar los objetos que se devolvern.

Group by into : permite realizar una agrupacin de datos.

Select: permite especificar los objetos/datos que debe devolver la peticin.

A continuacin se muestra un ejemplo de peticin LINQ que obtiene informacin de los


procesos que estn en ejecucin 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 peticin permite obtener el identificador y la etiqueta de aquellos procesos que estn
en ejecucin en un ordenador cuya cantidad de memoria asignada es estrictamente superior
a 20 MB. Adems, devuelve los registros por orden alfabtico inverso segn su etiqueta.
Se utilizarn las peticiones LINQ en la implementacin de reglas y servicios y
procesamientos de negocio en nuestras aplicaciones.

3. Los operadores de peticin


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 condicin, el Framework .NET ofrece
varios operadores de peticin implementados en forma de mtodos de extensin. A
continuacin se muestran algunos de ellos que se pueden aplicar a una peticin LINQ
realizada sobre un grupo de objetos:

ToList(): permite obtener el conjunto de objetos devuelto por la peticin en forma


de una coleccin genrica.

First(): permite obtener el primer objeto devuelto por la peticin.

FirstOrDefault(): permite obtener el primer objeto devuelto por la peticin. Si la


peticin 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 peticin.

Count(): permite obtener el nmero de objetos devuelto por la peticin.

Where(): permite obtener un subconjunto de objetos que cumplan una condicin.

OrderBy(): permite ordenar los objetos.

Select(): permite realizar una proyeccin de datos sobre los objetos o datos que
contienen.

Se pueden usar estos operadores de peticin para escribir un procesamiento idntico a la


peticin 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();

En esta instruccin, la utilizacin de operadores de peticin requiere el uso de expresiones


lambda para definir una expresin booleana que permita filtrar, una propiedad de
ordenacin y seleccionar los datos que se desean devolver.

LINQ Tutorial for Beginners

LINQ
LINQ is Microsofts 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");
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:
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 expressions
i => ((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 trees
IEnumerable<int> numsLessThanFour = nums.Where(i => i < 4).OrderBy(i => i);

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 methods 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
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.

Introducing LINQ Part 1

Published: 3/12/2007
By: 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!

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 collection
01.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.

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. 1
01.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 method
1.[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 query
01.public static void Example2()
02.{

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


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. 4
01.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.}

Figure 6: Cached anonymous delegate methods for their respective Where and orderby delegates
defined in Fig. 5
1.[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
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).
Lambda expressions

Figure 6: Same example as Fig. 4 but using lambda expression and extension methods
1.public static void Example3()
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. 6
01.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.

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.

LINQ to Entities: Basic Concepts and


Features
Introduction
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 LINQLanguage 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 LINQLanguage 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

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.

ORMObject-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 precompiler 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
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, lets 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.

LINQ to Entities
Now lets 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.

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 SQLlike 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 dont 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:

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, lets
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 higherlevel 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.
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

Features

LINQ to SQL

LINQ to Entities

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
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 TestLINQ
2. From Solution Explorer, right-click on the Solution item and select Add | New Project
from the context menu
3. 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 modelan 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:

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.

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
lets 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.

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 dont 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:

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:

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

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:

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 : ObjectContext
public partial class Product : EntityObject
public partial class Category : EntityObject
public 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

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 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();
}

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 products 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 beverages 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 product
Product 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 product
IQueryable<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.
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;
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 lets 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"
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 method
Console.WriteLine("The SQL statement is:" + beverages.ToTraceString());
and we also need to add a using statement to import the namespace for
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)
{
// 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

the QueryObject class:

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:

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, lets 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",
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:

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 objects 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 statement
decimal? 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:

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 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)
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);
}

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 dont 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 dont see the query statement to get the cheapest products.

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
[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)


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.

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.
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],
[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 dont 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,
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 hadnt 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();
}

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
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-toentities/book.

Anda mungkin juga menyukai