views:

133

answers:

2

Hi;

I feel my question is pretty dumb, or another way to put it is : I'm too lost in my code to see a workaround for now. Stay too long on a problem, and your vision becomes narrower and narrower ><. Plus I'm not good enough with inheritance, polymorphism and so

Here is the idea : I have multiple list of derived class, and I would like to call generic functions on those lists (accesing and modifying members of the base class). I feel there is something to do with inheritance, but I don't manage to make it work as I want for now .

Here is a very simple example of what I'm intending to do :

class Baseclass
{
    public int ID;
    public string Name;
}
class DerivedClass1 : Baseclass
{
}

private void FuncOnBase(List<Baseclass> _collection)
{
    // ...

    foreach (Baseclass obj in _collection)
    {
        ++obj.ID;
    }

    // ...
}
private void FuncTest()
{
    List<DerivedClass1> collection1 = new List<DerivedClass1>();
    collection1.Add(new DerivedClass1() { ID = 1 });
    collection1.Add(new DerivedClass1() { ID = 2 });
    collection1.Add(new DerivedClass1() { ID = 3 });

    FuncOnBase(collection1);   //  ==> forbidden, cannot convert the derived class list to the base class list
}
+6  A: 

Gotta love variance. A List<DerivedClass1> is not a List<Baseclass> - otherwise, FuncOnBase could attempt to add a Baseclass to the list, and the compiler wouldn't spot it.

One trick is to use a generic method:

private void FuncOnBase<T>(List<T> _collection) where T : Baseclass
{
    // ...

    foreach (T obj in _collection)
    {
        obj.ID++;
    }

    // ...
}

In terms of the example I presented above - note that we are able to add a T to the list; useful in particular if we add the T : new() constraint, or pass in (for example) a params T[].

Note also that IEnumerable<T> becomes covariant in C# 4.0 / .NET 4.0, so if you passed in just an IEnumerable<Baseclass> (rather than a list) it would work "as is":

private void FuncOnBase(IEnumerable<Baseclass> _collection)
{
   ///...
}
Marc Gravell
Gotta love the fact that I guessed this was your post after reading just 3 words :)
Jon Skeet
Am I becoming too predictable?
Marc Gravell
Thanks a lot, very usefull idea :)
Chouppy
+2  A: 

If you're only doing a foreach, declare FuncOnBase(IEnumerable<Baseclass> collection), which you can call from FuncTest like this:

FuncOnBase(collection1.Cast<Baseclass>());

When you declare a method with a List<T> parameter but only use its IEnumerable<T> features, you're adding API constraints that mean nothing in your code.

280Z28
Woops, thanks to you too for pointing this out.
Chouppy