Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

understanding nested generic classes in C# with quiz

While talking with a colleague about C#, he showed me some C# code which I had to predict the output of. This looked simple in the first place, but it wasn't. I can not really understand why C# acts this way.

The code:

public class A<T1> {     public T1 a;      public class B<T2> : A<T2>     {         public T1 b;          public class C<T3> : B<T3>         {             public T1 c;         }     } }  class Program {     static void Main(string[] args)     {         A<int>.B<char>.C<bool> o = new A<int>.B<char>.C<bool>();          Console.WriteLine(o.a.GetType());         Console.WriteLine(o.b.GetType());         Console.WriteLine(o.c.GetType());          Console.ReadKey();     } } 

The output is:

System.Boolean System.Char System.Int32 

Correct me if I'm wrong, but I understand that o.a is of type bool because C<T3> inherits from B<T3> and B<T2> inherits from A<T2>. And I can also slightly understand that o.c is of type int because the type of c is T1 which it gets from the outer class (I think).

My head is almost exploding when I try to figure out why o.b is of type char. Can some one explain this to me?

like image 838
Memet Olsen Avatar asked Jan 09 '13 14:01

Memet Olsen


2 Answers

This is an old puzzle, and it is quite difficult. When I gave it to Anders himself he didn't get the answer right the first time!

I think the version your coworker gave you is from Cyrus's blog:

http://blogs.msdn.com/b/cyrusn/archive/2005/08/01/446431.aspx

A slightly simpler version is on my blog.

http://blogs.msdn.com/b/ericlippert/archive/2007/07/27/an-inheritance-puzzle-part-one.aspx

The solution to my version is here:

http://blogs.msdn.com/b/ericlippert/archive/2007/07/30/an-inheritance-puzzle-part-two.aspx

Briefly, the reason for the confusing behaviour is that when you have a name that exists both in an outer class and a base class, the base class "wins". That is, if you have:

public class B {   public class X {} }  public class P {   public class X   {     public class D : B     {       public class N : X {}     }   } } 

Then P.X.D.N inherits from B.X, not from P.X. The puzzle makes nested generic types in such a way that the same declaration can be named via both the "outer" and "base" search paths, but has different meanings in each because of generic construction.

Anyway, read the explanation on the blog posts, and if its still not clear, ask a more specific question.

like image 134
Eric Lippert Avatar answered Sep 23 '22 17:09

Eric Lippert


Ok, my first answer was wrong. The nesting is important:

in o.b.GetType() b is the member of the surrounding class which is instantiated as B<char> which inherits from A<char> which in turn makes T1 equal to char. What's not quite clear is the following (manual instantiation for A_int.B_char.C_bool):

public class A_bool {     public bool a;      public class B_bool : A_bool     {         public bool b;     } }  public class A_char {     public char a;      public class B_bool : A_bool     {         public char b;     } }  public class A_int {     public int a;      public class B_char : A_char     {         public int b;          public class C_bool : A_char.B_bool         {             public int c;         }     } } 

Here C_bool could have been derived from A_bool.B_bool as well, right? But since we're nested in A_char that's preferred.

like image 45
CubeSchrauber Avatar answered Sep 24 '22 17:09

CubeSchrauber