I've got an object, which I'll call MyObject. It's a class that controls a particular data row.
I've then got a collection class, called MyObjectCollection:
public class MyObjectCollection : List<MyObject> {}
Why can I not do the following:
List<MyObject> list = this.DoSomethingHere();
MyObjectCollection collection = (MyObjectCollection)list;
Thanks in advance.
Edit: The error is InvalidCastException
My guess is that DoSomethingHere
doesn't return an instance of MyObjectCollection
.
Let's get rid of all the generics etc here, as they're not relevant. Here's what I suspect you're trying to do:
public static object CreateAnObject()
{
return new object();
}
object o = CreateAnObject();
string s = (string) o;
That will fail (at execution time) and quite rightly so.
To bring it back to your code, unless DoSomethingHere
actually returns a MyObjectCollection
at execution time, the cast will fail.
Because a List<MyObject>
is not a MyObjectCollection. The reverse is true: you could cast a MyObjectCollection to a List because MyObjectCollection inherits from List<MyObject>
and thus, for all intents and purposes, IS A List<MyObject>
.
The only thing you can do is to define a constructor on MyObjectCollection that takes an Ienumerable as a parameter and initalizes itself with the data in the other one, but that will make a new object containing the same data:
public class MyObjectCollection : List<MyObject>
{
public MyObjectCollection(IEnumerable<MyObject> items)
{
Addrange(items);
}
}
UPDATE:
As noted in the comment, you COULD have the cast succeed at runtime, provided that DoSomething actually returns an instance of MyObjectCollection. If it does, the object effectively is a MyObjectCollection, and the cast is completely legal.
I'd have to say, it is bad practice in my view to upcast something like that. If the function returns a List, you should not rely on a specific implementation of List. Either modify the return type of DoSomething, if you own that function, and return a MyObjectCollection, or deal with it as a list.
Without knowing what exactly is created inside DoSomething() we have to assume either:
You have a misunderstanding about the inheritence in .Net.
you have
A : B
B DoSomething()
{
return new B();
}
// then this is
B b = new B();
A a = (A)b;
Clearly b is a B but not an A. B might look much like A but it is not (if you traverse the parentage of b you won't find A anywhere)
This is true irrespective of the Generics involved (though that sometimes can cause situations where something that could work doesn't see the co-contra variance in c# 4.0)
or
A : B
B DoSomething()
{
return new A();
}
// then this is
B b = new A();
A a = (A)b;
Which in the absence of Generics will work.
You can't do it because (I guessing) the list instance returned from DoSomethingHere isn't derived from MyObjectCollection
You could create an implicit operator that would allow you to convert between your object and the list. You would need an constructor that takes a list and to property that returns the underlaying list.
public static implicit operator List<MyObject>(MyObjectCollection oCollection)
{
//Convert here
return MyObjectCollection.BaseList;
}
public static implicit operator MyObjectCollection(List<MyObject> oList)
{
//Convert here
return new MyObjectCollection(oList);
}