understanding nested generic classes in C# with quiz

C#GenericsInheritanceNested

C# Problem Overview


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?

C# Solutions


Solution 1 - C#

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.

Solution 2 - C#

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMemet OlsenView Question on Stackoverflow
Solution 1 - C#Eric LippertView Answer on Stackoverflow
Solution 2 - C#CubeSchrauberView Answer on Stackoverflow