2009-07-26 11 views
28

Dada una sencilla jerarquía de herencia: persona -> estudiante, profesor, PersonalLINQ: De una lista de tipo T, recuperar sólo los objetos de una determinada subclase S

Decir que tengo una lista de personas, L. En esa lista hay algunos estudiantes, maestros y personal.

Usando LINQ y C#, ¿hay alguna manera de que yo pueda escribir un método que pueda recuperar solo un tipo particular de persona?

Sé que puedo hacer algo como:

var peopleIWant = L.OfType<Teacher>(); 

Pero yo quiero ser capaz de hacer algo más dinámico. Me gustaría escribir un método que recupere resultados para cualquier tipo de Persona que se me ocurra, sin tener que escribir un método para cada tipo posible.

+1

Por qué no crear un método genérico? –

+0

Creo que eso es lo que hizo Mladen Prajdic. Ni siquiera lo había pensado, pero ahora que lo veo, parece muy razonable. – Hythloth

Respuesta

41

usted puede hacer esto:

IList<Person> persons = new List<Person>(); 

public IList<T> GetPersons<T>() where T : Person 
{ 
    return persons.OfType<T>().ToList(); 
} 

IList<Student> students = GetPersons<Student>(); 
IList<Teacher> teacher = GetPersons<Teacher>(); 

EDIT: añadido la restricción dónde.

+0

Ah, esto se ve maravilloso. Soy nuevo en LINQ, y no estoy especialmente bien versado en genéricos, pero esto parece ser precisamente lo que quiero. ¡Gracias!. – Hythloth

+0

No es necesario llamar a ToList sobre el resultado de GetPersons , ya que devuelve un IList ... –

+1

Es posible que desee colocar una restricción de "donde T: Persona" solo para evitar listas vacías debido a errores ortográficos, etc. –

7

Esto debería hacer el truco.

var students = persons.Where(p => p.GetType() == typeof(Student)); 
+0

Gracias por su aporte. Sabía que algo como esto era posible; Quería extender la idea a algo más genérico. Mladen Prajdic sugirió que use un Método genérico, que es algo que no se me había pasado por la cabeza. – Hythloth

2

usted puede hacer esto:

IEnumerable<Person> GetPeopleOfType<T>(IEnumerable<Person> list) 
    where T : Person 
{ 
    return list.Where(p => p.GetType() == typeof(T)); 
} 

Pero lo único que han hecho es reescribir método() con una versión más segura que utiliza tipo estático comprobación para garantizar que se pasa en una persona OfType de LINQ. Aún no puede usar este método con un tipo determinado en tiempo de ejecución (a menos que use el reflejo).

Por eso, en lugar de utilizar los genéricos, que tendrá que hacer la variable tipo de un parámetro:

IEnumerable<Person> GetPeopleOfType(IEnumerable<Person> list, Type type) 
{ 
    if (!typeof(Person).IsAssignableFrom(type)) 
     throw new ArgumentException("Parameter 'type' is not a Person"); 

    return list.Where(p => p.GetType() == type); 
} 

Ahora se puede construir algún tipo de forma dinámica y lo utilizan para llamar a este método.

+0

Gracias por introducirme en la restricción de "dónde" para genéricos. Tan pronto como especifiqué esa restricción, ahora puedo confiar en el soporte de Intellisense en los métodos y propiedades disponibles de mi tipo de persona. – Hythloth

0

Por lista general, utilizando delegate:

public List<T> FilterByType(List<T> items, Type filterType) 
{ 
    return items.FindAll(delegate(T t) 
    { 
     return t.GetType() == filterType; 
    }); 
} 
Cuestiones relacionadas