views:

355

answers:

7

Duplicate

In C#, why can’t a List object be stored in a List variable

Here is my code:

public class Base
    {
        protected BindingList<SampleBase> m_samples;

        public Base() { }
    }

    public class Derived : Base
    {
        public Derived()
        {
            m_samples = new BindingList<SampleDerived>();
        }
    }

SampleDerived is derived from SampleBase

According to the inheritance logic, I should be able to do this. However, it doesn't compile - the error says that SampleBase can not be be implicitly converted to SampleDerived type. What gives?

I am using c# 2.0

A: 

Generics cannot be casted.

You can cast List<MyClass> to IList<MyClass> or even IList, but this would be illegal:

List<Object> = new List<MyClass>();
Babak Naffas
Hah They stripped your angle brackets too
drs9222
C# doesn't have templates. Generics aren't templates.
Pavel Minaev
Subtle difference, but thanks for the info. Updated the answer.
Babak Naffas
+2  A: 

I can understand why you would think that but generics don't work that way. :(

BindingList<SampleDerived> does not actually derive from BindingList<SampleBase>
drs9222
+4  A: 

You're trying to use covariance, which is not supported by C# 3.0 and earlier (but will be in C# 4.0). You can still add objects of type SampleDerived into m_samples, but the list's generic type will need to be SampleBase.

Edit: So Pavel is right, C# 4.0 doesn't actually help with this. It would if m_sample were defined as IBindingList<SampleBase> using (fictional) covariant interface IBindingList<out T>.

dahlbyk
This particular scenario won't be helped by covariance support in C# 4.0. For one thing, C# 4.0 only supports variance for interfaces, not for classes. For another (and more importantly), `BindingList<T>` (and any other mutable collection class) is not covariant.
Pavel Minaev
@Pavel Minaev: "C# 4.0 only supports variance for interfaces[.]" And delegates.
Jason
you may find Eric Lippert's articles on covariance and contravariance interesting. Part 1 - http://blogs.msdn.com/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx
Russ Cam
Agree, this won't work in C# 4.
Alex Yakunin
A: 

This type of generic variance is not supported in C#2 or 3. It will be supported in C#4. (See comment.) Eric Lippert has a series of blog posts on this subject that goes into enough detail to kill any unwary developer. :)

JP Alioto
This particular scenario won't be helped by covariance support in C# 4.0. For one thing, C# 4.0 only supports variance for interfaces, not for classes. For another (and more importantly), BindingList<T> (and any other mutable collection class) is not covariant.
Pavel Minaev
There's enough pure concentrated variance in there to turn you all into hermit crabs, so be careful.
Eric Lippert
+1  A: 

A BindingList<SampleDerived> is not a BindingList<SampleBase> -- you can add a SampleBase to the latter, but not to the former.

Steve Gilham
A: 

Most likely you must simply create the list instance in your base class, and freely use it in derived.

public class Base
{
    protected BindingList<SampleBase> m_samples = new BindingList<Derived>();

    public Base() { }
}

public class Derived : Base
{
    public FwdRunData()
    {
        m_samples.Add(new Derived>());
    }
}
Alex Yakunin
Except that I am going to have several classes that are derived from SampleBase....so my whole point was that I won't have to declare and create m_samples in each class that has been derived from Base.
gnomixa
A: 

The people pointing you to Eric Lippert's excellent posts on variance are right, but here's a short example showing what would go wrong. I've just added a new method to the base class and I'm using another derived sample class. What would happen when the BreakDerived method is called on an instance of your original Derived class? You can't add an instance of SampleDerived2 to the BindingList<SampledDerived>.

public class Base {
    protected BindingList<SampleBase> m_samples;
    public Base() { }
    public BreakDerived() { m_samples.Add(new SampleDerived2()); }    
}

public class Derived : Base {
    public Derived() { m_samples = new BindingList<SampledDerived>(); }
}
kvb