Reputation: 12490
I have a list of object of different types; they can be of type Lemon, Strawberry, Grape. They all inherit Fruit. They may also implement interfaces like ISour, IGrowOnTree etc.
Now, I'd like to write a method to get, from said list, all the instances that can be converted to a certain type.
What I do now is get all the elements and locally in my caller function filter them like:
List<Fruit> myFruits = fruitBasket.GetAllTheFruits();
List<ISour> mySourFruit = new List<ISour>();
foreach (var fruit in myFruit)
{
var sourFruit = fruit as ISour;
if (sourFruit != null)
mySourFruit.Add(sourFruit);
}
I moved this logic inside my Basket so I don't have to rewrite the filter all the time. I was able to do this with generics, like:
public function List<T> GetFruits<T>() where T : class
{
List<T> result = new List<T>();
foreach (var fruit in this._allFruits)
{
var fruitAsT = fruit as T;
if (fruitAsT != null)
result.Add(fruitAsT);
}
return result;
}
For the sake of argument, is it possible to write this in the form:
public function List<Fruit> GetFruits(Type type)
So instead of calling:
var myFruits = basket.GetFruits<ISour>();
I'd rather call:
var myFruits = basket.GetFruits(typeof(ISour))
or something similar (so, passing the type as argument instead of using a generic)?
Upvotes: 0
Views: 47
Reputation: 16017
You can keep the generics solution and pass in the result list to help the compiler determine the applicable type:
namespace FruitListTest
{
class Fruit { }
class Apple : Fruit { }
class Program
{
static List<Fruit> fruitList = new List<Fruit>();
public static void GetSpecificFruits<specificFruit>(List<specificFruit> specificFruits)
where specificFruit : Fruit
{
foreach (var fruit in fruitList)
{
var fruitAsT = fruit as specificFruit;
if (fruitAsT != null)
specificFruits.Add(fruitAsT);
}
}
static void Main(string[] args)
{
List<Apple> applesInFruits = new List<Apple>();
GetSpecificFruits(applesInFruits);
}
}
}
This solution can be beautified in a number of ways: One could return the list to simplify chaining etc; one could return the number, or a boolean (any apples in there?). One could pass in two arguments (the source list, too) to have a freestanding function. One could make either one of the two arguments a this
parameter, so that a call like fruits.GetSpecificFruits(appleList)
or appleList.FillFrom(fruitList)
would be possible. If the generic fruit list is always the same, the call boils down to appleList.Fill()
(fill it implicitly from fruitList
) which seems elegant.
Upvotes: 0
Reputation: 26213
Without the generics, you have to use the various instance methods available on Type
. Type.IsInstanceOfType
is the most obvious in this case:
public List<Fruit> GetFruits(Type type)
{
var result = new List<Fruit>();
foreach (var fruit in this._allFruits)
{
if (type.IsInstanceOfType(fruit))
{
result.Add(fruit);
}
}
return result;
}
Upvotes: 1