Reputation: 6016
I'm trying to understand why this cast doesn't work:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CastTest {
class Foo {}
// I want to use this kind of like a typedef, to avoid writing List<Foo> everywhere.
class FooList : List<Foo> {}
class Program {
static void Main(string[] args) {
FooList list = (FooList) Program.GetFooList();
}
// Suppose this is some library method, and i don't have control over the return type
static List<Foo> GetFooList() {
return new List<Foo>();
}
}
}
This generates a runtime error:
InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List`1[CastTest.Foo]' to type 'CastTest.FooList'.
Can anyone explain why this doesn't work, and whether I can get around this somehow?
Upvotes: 5
Views: 794
Reputation: 5222
You cant upcast; but you could create a new instance of FooList and the contents to it
class Foo { }
// I want to use this kind of like a typedef, to avoid writing List<Foo> everywhere.
class FooList : List<Foo> {}
class Program
{
static void Main(string[] args)
{
FooList l = new FooList();
l.AddRange(GetFooList().Select(foo => foo));
Console.ReadLine();
}
// Suppose this is some library method, and i don't have control over the return type
static List<Foo> GetFooList()
{
return new List<Foo>();
}
}
Upvotes: 1
Reputation: 9588
You cannot automatically cast from a parent class to a derived class: just because the object you're attempting to cast is a List<Foo>
doesn't necessarily make it a FooList
.
Check out:
You could write an operator that converts a List<Foo>
to a FooList
, perhaps using AddRange
to populate the values, such as:
class FooList
{
public explicit operator FooList(List<Foo> arg)
{
FooList result = new FooList();
result.AddRange(arg);
return result;
}
}
Also, it may be better to just use a using
alias:
http://msdn.microsoft.com/en-us/library/sf0df423(v=vs.80).aspx
using FooList = List<Foo>;
This way you're not actually passing around needless derived classes.
Upvotes: 5
Reputation: 424
Because not all List are FooList. For example, I could have:
public class AnotherFooList : List<Foo>
{
public object AdditionalPropery {get; set; }
}
It too inherits from List but is not the same as a FooList and a FooList is not the same as it.
Upvotes: 2
Reputation: 15076
Since you know that a FooList
is in reality just another name for a List<Foo>
it may seem strange. But given that a FooList
could contain members itself, it becomes apparant that the compiler should not allow the cast. Imagine you at a later time introduce a method (Bar()
) on the FooList
. This method is not present on List<Foo>
and the type system would simply break if the assignment (or cast) was allowed.
Upvotes: 1
Reputation:
The closest C# has to a typedef is called a using alias directive:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CastTest {
using FooList = List<Foo>;
class Foo {}
class Program {
static void Main(string[] args) {
FooList list = Program.GetFooList();
}
// Suppose this is some library method, and i don't have control over the return type
static List<Foo> GetFooList() {
return new List<Foo>();
}
}
}
What you have creates a derived class FooList
, but this creates an alias FooList
. It isn't somewhat compatible with List<Foo>
, it is List<Foo>
.
Upvotes: 2
Reputation: 1499740
This method:
static List<Foo> GetFooList() {
return new List<Foo>();
}
... doesn't return a FooList
. Your code is effectively like this:
FooList list = (FooList) new List<Foo>();
That's simply not going to work. It's as invalid as:
string x = (string) new object();
You wouldn't expect that to work, would you? So why would your FooList
version work?
Upvotes: 4
Reputation: 3907
Just because your FooList is a List doesn't make the List a FooList.
Upvotes: 7