2009-07-26 8 views
28

eine einfache Vererbungshierarchie Gegeben: Person -> Student, Lehrer, MitarbeiterLINQ: Aus einer Liste vom Typ T, Abrufen nur Objekte einer bestimmten Unterklasse S

Sagen wir, ich habe eine Liste von Personen, L. In dieser Liste sind einige Schüler, Lehrer und Mitarbeiter.

Mit LINQ und C#, gibt es eine Möglichkeit, ich könnte eine Methode schreiben, die nur eine bestimmte Art von Person abrufen konnte?

Ich weiß, ich kann so etwas tun:

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

Aber ich möchte in der Lage sein, etwas mehr Dynamik zu tun. Ich möchte eine Methode schreiben, die Ergebnisse für jede Art von Person, die ich mir vorstellen konnte, abruft, ohne eine Methode für jeden möglichen Typ schreiben zu müssen.

+1

Warum nicht eine generische Methode erstellen? –

+0

Ich denke, das ist es, was Mladen Prajdic getan hat. Ich hatte nicht einmal daran gedacht, aber jetzt, wo ich es sehe, scheint es sehr vernünftig. – Hythloth

Antwort

41

Sie können dies tun:

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: hinzugefügt, um den in den Zwang.

+0

Ah, das sieht wunderbar aus. Ich bin neu bei LINQ und nicht besonders versiert in Generika, aber das scheint genau das zu sein, was ich will. Vielen Dank!. – Hythloth

+0

Kein Aufruf ToList auf das Ergebnis von GetPersons , da es bereits eine IList ... –

+1

Sie möchten möglicherweise eine Einschränkung von "wo T: Person", um leere Listen aufgrund von Tippfehlern usw. zu vermeiden. –

7

Dies sollte den Trick tun.

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

Vielen Dank für Ihre Eingabe. Ich wusste, dass so etwas möglich war; Ich wollte die Idee auf etwas allgemeineres erweitern. Mladen Prajdic schlug vor, eine generische Methode zu verwenden, was mir nicht in den Sinn gekommen war. – Hythloth

2

Sie können dies tun:

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

Aber alles, was Sie wirklich getan haben, ist neu schreiben LINQ OfType() -Methode mit einer sichereren Version, die vom statischen Typ verwendet Überprüfung Sie in einer Person passieren zu gewährleisten. Sie können diese Methode immer noch nicht mit einem Typ verwenden, der zur Laufzeit festgelegt wird (es sei denn, Sie verwenden die Reflektion).

Dafür anstatt die Verwendung von Generika, werden Sie die Variable vom Typ einen Parameter vornehmen:

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

Jetzt können Sie irgendeine Art dynamisch konstruieren und verwenden Sie es, diese Methode zu nennen.

+0

Vielen Dank für die Einführung in die "Where" -Restriktion für Generika. Sobald ich diese Einschränkung angegeben habe, kann ich mich nun auf die Intellisense-Unterstützung für die verfügbaren Methoden und Eigenschaften meines Personentyps verlassen. – Hythloth

0

Für allgemeine Liste mit delegate:

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