Clases consultables desde Linq

No se vosotros, pero a mí me da especial pereza cuando tengo que crear métodos para buscar determinados valores dentro de una colección de objetos, ya sé que los métodos de búsqueda vienen a ser siempre los mismos y la implementación no varía mucho de una vez a otra, pero cuando has de obtener ya valores calculados o rangos de valores o combinaciones más perversas la cosa cambia. Para facilitarnos este trabajo tenemos linq y ahora explicaremos cómo construir nuestras clases para que puedan ser consultadas mediante linq.

Nota: Este articulo lo redacte ya hace un tiempo para documentar un posible uso en el trabajo.

La clase base

Antes de nada debemos construir la clase que contendrá la información que almacenamos, para esta demos optaremos por la original clase persona, con los atributos nombre, apellidos, edad, dni y sexo.

class Persona {
string _nombre;
string _apellidos;
int _edad;
string _dni;
int _sexo;

public string nombre {
get { return _nombre; }
set { _nombre = value; }
}
public string apellidos {
get { return _apellidos; }
set { _apellidos = value; }
}
public int edad {
get { return _edad; }
set { _edad = value; }
}
public string dni {
get { return _dni; }
set { _dni = value; }
}
public int sexo {
get { return _sexo; }
set { _sexo = value; }
}
}

Colección de objetos

Ahora pasamos a la chicha, hemos de diseñar una clase que contenga la colección de objetos sobre los cuales queremos consultar. Para que linq pueda realizar consultas esta colección debe implementar el interface IEnumerable, este interface expone el IEnumerator interno que permite una iteración simple a través de los objetos que contiene la colección. Como se puede ver, también debemos implementar el interface IEnumerator dentro de la colección. Es importante ver que el IEnumerator se define dentro de la clase colección no fuera, ya que ha de poder acceder a la colección de objetos, en nuestro caso conjuntoPersonas.

También hay que destacar que debemos implementar el interface con establecimiento inflexible de tipos, es decir que definimos que tipo de objeto contiene, <Persona>, si no se hiciera así Linq no sabría que propiedades tiene el objeto y no podría realizar las consultas. Además esta forma nos da una mayor seguridad de tipos y es más eficiente que las colecciones que nosotros creemos con establecimiento inflexible de tipos.

Veamos la clase y su implementación.

class Personal : IEnumerable<Persona>
{
private Persona[] conjuntoPersonas;
public void add(Persona nuevaPersona)
{
int l;
if (conjuntoPersonas == null)
{
conjuntoPersonas = new Persona[1];
conjuntoPersonas[0] = nuevaPersona;
l = 1;
}
else
{
l = conjuntoPersonas.Length;
Persona[] _arr = new Persona[l+1];
conjuntoPersonas.CopyTo(_arr, 0);
_arr[l] = nuevaPersona;
conjuntoPersonas = _arr;
}
}
public IEnumerator<Persona> GetEnumerator()
{
return new PersonaEnumerator(conjuntoPersonas);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return new PersonaEnumerator(conjuntoPersonas);
}

private class PersonaEnumerator : IEnumerator<Persona>
{
private int position = -1;
private Persona[] conjuntoPersonasEnumerator;
public PersonaEnumerator(Persona[] grupo)
{
conjuntoPersonasEnumerator = grupo;
}
public bool MoveNext()
{
position++;
if (position < conjuntoPersonasEnumerator.Length)
return true;
else
return false;
}
// Reset the enumeration by setting the position to -1
public void Reset()
{
position = -1;
}
// Return the current object
Object System.Collections.IEnumerator.Current
{
get { return conjuntoPersonasEnumerator[position]; }
}
public Persona Current
{
get { return conjuntoPersonasEnumerator[position]; }
}

Hay que fijarse que la funcion GetEnumerator del interface IEnumerable y la propiedad Current del IEnumerator están sobre cargadas, esto se debe a que para cumplir con el interface hace falta que estén implementadas para objetos genéricos y para el objeto específico, además en mis pruebas, cuando implementaba las funciones con objetos genéricos tenía que indicar toda la ruta hasta la función del interface para que no me diera error.

GetEnumerator

public IEnumerator<Persona> GetEnumerator() (objeto específico)
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() (objeto genérico)

Current

Object System.Collections.IEnumerator.Current (objeto genérico)
public Persona Current (objeto específico)

Con esto ya tenemos nuestra clase conultable en Linq y podremos hacer consultas como por ejemplo, las persona con mas de 30 años:

var c = from ps in p where ps.edad > 30 select ps;

O la media de edad de cada sexo:

var res = from ps in p group ps by ps.sexo into ps2 select new {sexo = ps2.Key, avg = ps2.Average(c => c.edad)};

Comentarios

La potencia del Linq la veremos sobre todo cuando dispongamos de diversas clases y hagamos joins entre ellas, simplificando mucho el proceso de cruzar las referencias.

Hemos de tener en cuenta que, para tareas sencillas, Linq no es optimo. Recorrer un array buscando un valor concreto, por ejemplo, es altamente optimizado por el compilador dando como resultado un procesos hasta 40 veces más rápido.

descarga proyecto de ejemplo

P.D: No soy la persona que mejor se explica del mundo así que si algo no esta bien explicado o hace falta que le de otra vuelta decírmelo.

Comentarios (1)

BRAD21 de Julio, 2010 a las 17:55


MedicamentSpot.com. Canadian Health&Care.No prescription online pharmacy.Special Internet Prices.Best quality drugs. High quality pills. Buy pills online

Buy:Arimidex.Lumigan.Retin-A.Human Growth Hormone.Petcam (Metacam) Oral Suspension.Valtrex.Synthroid.Zyban.Actos.Prevacid.Mega Hoodia.100% Pure Okinawan Coral Calcium.Zovirax.Accutane.Prednisolone.Nexium….

Deja un comentario

Tu comentario