Puzzle from an Interview with Eric Lippert: Inheritance and Generic Type Setting

Can someone explain to me why the below code outputs what it does?

I'll explain briefly here; a longer explanation can be found here.

The crux of the matter is determining the meaning of B in class C : B. Consider a version without generics: (for brevity I'll omit the publics.)

class D { class E {} }
class J {
  class E {}
  class K : D {
    E e; // Fully qualify this type
  }
}

That could be J.E or D.E; which is it? The rule in C# when resolving a name is to look at the base class hierarchy, and only if that fails, then look at your container. K already has a member E by inheritance, so it does not need to look at its container to discover that its container has a member E by containment.

But we see that the puzzle has this same structure; it's just obfuscated by the generics. We can treat the generic like a template and just write out the constructions of A-of-string and A-of-int as classes:

class A_of_int 
{
  class B : A_of_int
  {
    void M() { Write("int"); }
    class C : B { } // A_of_int.B
  }
}
class A_of_string
{
  class B : A_of_int
  {
    void M() { Write("string"); }
    class C : B {} // still A_of_int.B
  }
}

And now it should be clear why A_of_string.B.M() writes string but A_of_string.B.C.M() writes int.


Method M inside B prints typeof(T) of A<T>, A is parent class of B.

So irrespective of whether B is derived from whatever, M prints typeof(T) that is String.

So A<T>.B.M prints nearest A's T.

So A<string>.B.M will print string

Now, let us expand expression A<string>.B.C, which is equivalent to A<string>.B.A<int>.B (since C is A<int>.B), so method A<string>.B.A<int>.B.M will print nearest T.

A<string>.B.A<int>.B.M will print int


By the Introduction to Generics T is also available in nested class. That is case with class B which is nested into A. On the other hand C is nested into B and T of the B is available into C. As you can see T of the B is int and method called on C will use int as generic parameter.