2012-05-05 2 views
2

У меня есть базовый класс, называемый Fruits. У меня тогда есть несколько дочерних классов, скажем Banana:Fruit, Apple:Fruit и т. Д.найти объекты определенного класса из списка <>

У меня тогда есть список объектов разных типов, Банан, Яблоко, что угодно. Это выглядит следующим образом:

List<Fruits> f = new List<Fruits>{new Banana(), new Banana(), new Apple(), new Banana()}; 

Я хочу функцию, которая может взять список фруктов, а также тип и дать мне список только с объектами этого типа в списке. Поэтому, если я позвоню find_obj(f, Banana), (или что-то), он должен вернуть мне список, содержащий только бананы.

Возможно, я проявляю крайнее невежество, и я прошу прощения. Возможно ли это? Я знаю, что я мог бы сделать что-то вроде этого, если я знаю, что класс заранее:

public List<Fruit> GimmeBanana(List<Fruit> f) 
{ 
    List<Fruit> Output=new List<Fruit>{ }; 
    foreach(Fruit fr in f) 
    { 
     if (fr is Banana){ Output.Add(fr); } 
    } 
} 

Но я не знаю, как сделать эту работу для Любой класса.

ответ

12

Такой метод уже существует в рамках - OfType<T>:

List<Banana> bananas = f.OfType<Banana>().ToList(); 
+0

Awesome! это намного проще (и короче), чем там, где я возглавлял. –

1

Даже если вы должны использовать OfType как отмечает другие ответы, как опыт, вот как я бы написать свой метод:

public IEnumerable<Banana> GimmeBananas(List<Fruit> f) 
{ 
    if (f == null) yield break; //depending on what business logic you're looking for. 
    foreach(Fruit fr in f) 
    { 
     if (fr is Banana) yield return fr; 
    } 
} 
+0

+1 - foreach имеет тенденцию быть быстрее, чем linq (в зависимости от запроса), плюс это дает разработчику возможность выполнять бизнес-логику без циклирования дважды. –

+3

Возможно, вы захотите заменить Banana на T и добавить к методу подпись . Делает его общим, что ищет OP. –

0

Оператор LINQ OfType может использовать только элементы коллекции с соответствующим типом.

class Fruit { } 
class Banana : Fruit{} 
class Apple : Fruit{} 

static void Main(string[] args) 
{ 
    var fruits = new List<Fruit> { new Banana(), new Banana(), new Apple(), new Fruit() }; 
    int bananas = fruits.OfType<Banana>().Count(); // 2 
    int apples = fruits.OfType<Apple>().Count(); // 1 
    int fruitc = fruits.OfType<Fruit>().Count(); // 4 
    int exactFruits = GetOfExactType<Fruit,Fruit>(fruits).Count(); // 1 
} 


static IEnumerable<V> GetOfExactType<T, V>(IEnumerable<T> coll) 
{ 
    foreach (var x in coll) 
    { 
     if (x.GetType().TypeHandle.Value == typeof(V).TypeHandle.Value) 
     { 
      yield return (V)(object)x; 
     } 
    } 
} 

Этот оператор работает только в том случае, если у вас есть иерархическая иерархия. Если у вас есть, например, Яблоки в качестве базового класса производятся из фруктов, и у вас есть специализированные яблоки, такие как GoldenDelicius, RedDelicus, ... и вы хотите считать все яблоки, которые имеют тип яблока, но не производные, вы не можете сделать это с оператором OfType. Для этого вам все еще нужна дополнительная функция. В этом примере он называется GetOfExactType.

1

вам нужен универсальный метод, как:

public List<T> GimmeAnyOfType<T>(List<Fruit> f) 
    { 
     return f.OfType<T>().ToList(); 
    } 
Смежные вопросы