ccalboni
ccalboni

Reputation: 12490

How do I use "as" to check if an object is of a type passed by argument?

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

Answers (2)

Peter - Reinstate Monica
Peter - Reinstate Monica

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

Charles Mager
Charles Mager

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

Related Questions