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

前端 未结 5 594
我在风中等你
我在风中等你 2020-12-18 04:12

Can someone explain to me why the below code outputs what it does? Why is T a String in the first one, not an Int32, and why is it the opposite case in the next output?

5条回答
  •  执念已碎
    2020-12-18 04:43

    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.

提交回复
热议问题