views:

159

answers:

3

Given the following code:

class A<T>
{
  internal void Add(T obj) { }
}

class C { }

class B<T> where T : C
{
  public B()
  {
    A<T> a = new A<T>();
    a.Add(new C());
  }
}

The call to Add does not compile. It does when I cast it to T first:

a.Add((T)new C());

It might be the sleep deprivation, but what am I missing here?

If T is of type C (note the constraint on B), then why isn't A<T> equivalent to A<C>?

+3  A: 

because T could be a subclass of C.

you can't add a Animal bob = new Fish() to a List<Giraffe>

Jimmy
+4  A: 

Because if B were declared with a type of D, which would be a class which extends C, then adding a new C would violate the type.

Yishai
Thanks, that eluded me :)
JulianR
My mind is officially blown. :)
John Kraft
But only if this weren't .NET 4 with contravariance for D and C in B.
Jeff Yates
FYI, the new variance features only apply to delegate and interface types constructed with reference types.
Eric Lippert
+2  A: 

A.Add() is expecting a T. You're giving it a C. This is okay as long as the compiler knows that a C is a T.

But that's not what your constraint says. It only says that a T is a C, which is the opposite.

Joel Coehoorn
I find your explanation much easier to parse than Yishai's.
Brian