web-dev-qa-db-ja.com

LINQ:タイプTのリストから、特定のサブクラスSのオブジェクトのみを取得します

単純な継承階層があるとすると、Person-> Student、Teacher、Staff

人物リストLがあるとしましょう。そのリストには、生徒、教師、スタッフが含まれています。

LINQとC#を使用して、特定の種類の人物のみを取得できるメソッドを作成する方法はありますか?

私は次のようなことができることを知っています:

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

でももっとダイナミックなことができるようになりたいです。考えられるすべてのタイプのPersonの結果を取得するメソッドを作成します。可能なタイプごとにメソッドを作成する必要はありません。

32
Hythloth

あなたはこれを行うことができます:

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

編集:where制約を追加しました。

47
Mladen Prajdic

これでうまくいくはずです。

var students = persons.Where(p => p.GetType() == typeof(Student));
8
kareem

あなたはこれを行うことができます:

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

しかし、実際に行ったことは、LINQのOfType()メソッドを、静的型チェックを使用してPersonを確実に渡す安全なバージョンに書き換えることです。 (リフレクションを使用しない限り)このメソッドを実行時に決定される型で使用することはできません。

そのためには、ジェネリックスを使用するのではなく、型変数をパラメーターにする必要があります。

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

これで、いくつかの型を動的に構築し、それを使用してこのメ​​ソッドを呼び出すことができます。

2
Richard Berg

一般的なリストについては、delegateを使用します。

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