2

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

Community
  • 1
  • 1
sarsnake
  • 26,667
  • 58
  • 180
  • 286
  • 4
    Please look at this question: http://stackoverflow.com/questions/6557/in-c-why-cant-a-liststring-object-be-stored-in-a-listobject-variable – Pavel Minaev Jul 24 '09 at 22:57
  • @gnomixa: "According to the inheritance logic" => there is no inheritance logic; two different type parameterizations are not the same types (the members they effectively define are different), although covariance suggest that they have something in common (the relationship between the type-parameter arguments SampleBase and SampleDerived). C# 4.0 will support covariance. – Cecil Has a Name Jul 25 '09 at 15:31
  • Can someone share experiences on how to achieve what I want? Surely, it has been done before. All I see is theory and pointing out what's wrong. Can someone offer a WORKING solution that would achieve my objective? Thanks – sarsnake Jul 27 '09 at 22:59

7 Answers7

4

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
  • 75,175
  • 8
  • 100
  • 122
  • 6
    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` (and any other mutable collection class) is not covariant. – Pavel Minaev Jul 24 '09 at 22:59
  • 1
    @Pavel Minaev: "C# 4.0 only supports variance for interfaces[.]" And delegates. – jason Jul 24 '09 at 23:02
  • 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 Jul 24 '09 at 23:02
2

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,448
  • 3
  • 33
  • 41
1

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

Steve Gilham
  • 11,237
  • 3
  • 31
  • 37
0

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
  • 12,395
  • 3
  • 34
  • 49
0

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
  • 44,864
  • 6
  • 88
  • 112
  • 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 (and any other mutable collection class) is not covariant. – Pavel Minaev Jul 24 '09 at 23:00
  • There's enough pure concentrated variance in there to turn you all into hermit crabs, so be careful. – Eric Lippert Jul 26 '09 at 14:35
0

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
  • 6,330
  • 3
  • 33
  • 52
  • 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. – sarsnake Jul 24 '09 at 23:13
0

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
  • 54,864
  • 2
  • 91
  • 133