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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With