It is easy to check:
Console.WriteLine(new G2<C1>() is G1<C1>); // True
Console.WriteLine(new G1<C2>() is G1<C1>); // False
Console.WriteLine(new G2<C2>() is G1<C1>); // False
class C1{}
class C2:C1{}
class G1<T>{}
class G2<T>:G1<T>{}
Demo
The last two in general case are quite easy to explain. Imagine G1
being:
class G1<T>
{
public T Data { get; set; }
}
Then if new G1<C2>() is G1<C1>
would be true then the next would be possible -
((G1<C1>)new G1<C2>()).Data = new C1();
which obviously breaks type safety.
Something can be done with variance support in generic interfaces, but it is limited to interfaces.