Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
347 views
in Technique[技术] by (71.8m points)

c# - 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? Why is T a String in the first one, not an Int32, and why is it the opposite case in the next output?

This puzzle is from an interview with Eric Lippert

When I look through the code, I really have no idea if it's going to be an Int32 or a String:

public class A<T>
    {
        public class B : A<int>
        {
            public void M() { System.Console.WriteLine(typeof(T)); }
            public class C : B { }
        }
    }

    public class P
    {
        public static void Main()
        {            
            (new A<string>.B()).M(); //Outputs System.String
            (new A<string>.B.C()).M(); //Outputs System.Int32
            Console.Read();
        }
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...