I think I must be missing something, why can't I compile this:
class Foo<T> where T : Bar
{
T Bar;
}
abstract class Bar
{ }
class MyBar : Bar
{ }
static void Main(string[] args)
{
var fooMyBar = new Foo<MyBar>();
AddMoreFoos(fooMyBar);
}
static void AddMoreFoos<T>(Foo<T> FooToAdd) where T : Bar
{
var listOfFoos = new List<Foo<Bar>>();
listOfFoos.Add(FooToAdd); //Doesn't compile
listOfFoos.Add((Foo<Bar>)FooToAdd); //doesn't compile
}
You're make things a little bit more confusing than they need to be by using a list here... it's easiest to see the effect this way:
// This won't compile
Foo<Bar> fooBar = new Foo<MyBar>();
Given that this doesn't compile, it's then not surprising that you can't add a Foo<MyBar>
to a List<Foo<Bar>>
So why isn't a Foo<MyBar>
a Foo<Bar>
? Because generic classes aren't covariant.
Generic variance was only introduced in C# 4 - and it only works for interfaces and delegates. So you could (in C# 4) do:
IEnumerable<MyBar> x = new List<MyBar>();
IEnumerable<Bar> y = x;
but you couldn't do:
IList<MyBar> x = new List<MyBar>();
IList<Bar> y = x;
I have a whole talk about variance which you can download from the NDC 2010 video site - just search for "variance".
It doesn't compile because if you were to call your method with a Foo<int>
then the call will fail: you are trying to assume a specific type for your generic parameter.
What you need is to use var listOfFoos = new List<Foo<T>>()
instead, then the Add
should work.
(EDIT: equally, the cast would work if you used Foo<T>
- but you still can't assume in your code that T
is Bar
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With