2013-01-09 3 views
59

Во время разговора с коллегой о C# он показал мне код C#, который я должен был предсказать вывод. В первую очередь это выглядело просто, но это было не так. Я не могу понять, почему C# действует таким образом.понимание вложенных родовых классов в C# с викториной

Код:

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(); 
    } 
} 

Выход:

System.Boolean 
System.Char 
System.Int32 

Поправьте меня, если я ошибаюсь, но я понимаю, что o.a имеет тип BOOL, поскольку C<T3> наследует от B<T3> и B<T2> наследует от A<T2>. И я также могу понять, что o.c имеет тип int, потому что тип c равен T1, который он получает из внешнего класса (я думаю).

Моя голова почти взрывается, когда я пытаюсь понять, почему o.b имеет тип char. Может кто-то объяснить это мне?

+38

Я рад, что не поддерживаю код в вашей компании. – Default

+0

Интересный, но полный перебор для чего-нибудь практического. Я предполагаю, что это скорее академическая, чем работа? – JGilmartin

+4

@Default Почему? Потому что им нравится викторины друг другу по странному C# -коду? – Erix

ответ

40

Это старая головоломка, и это довольно сложно. Когда я отдал его самому Андерсу, он не получил ответ в первый раз!

Я думаю, что версия вашей Коллега дал вам из блога Кира:

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

Несколько упрощенная версия на моем блоге.

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

Решение моей версии здесь:

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

Вкратце, причина запутанным поведения является то, что, когда у вас есть имя, которое существует как во внешнем классе и базовый класс, базовый класс «выигрывает». То есть, если у вас есть:

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

Тогда P.X.D.N наследует от B.X, а не от P.X. Эта головоломка создает вложенные общие типы таким образом, что одно и то же объявление может быть названо как с помощью «внешних», так и «базовых» путей поиска, но имеет разные значения в каждом из-за общей конструкции.

В любом случае, прочитайте объяснение в сообщениях в блоге, и если его все еще не ясно, задайте более конкретный вопрос.

8

Хорошо, мой первый ответ был неправильным. Вложенности Важно:

в o.b.GetType() б является членом окружающего класса, который создаетс в качестве B<char>, который наследует от A<char> который, в свою очередь, делает Т1 равна обугливается. Что не совсем ясно, является следующее (ручной конкретизации для 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; 
     } 
    } 
} 

Здесь C_bool могли быть получены из A_bool.B_bool, а, верно? Но так как мы вложены в A_char, это предпочтительнее.

+1

Тогда почему o.c не bool? Потому что C наследует от B , который, в свою очередь, наследуется от A .. –

+1

Да, что вводит в заблуждение различие между наследованием и охватывающими типами. 'C ' заключен в 'B ', но наследуется от 'B ' – CubeSchrauber

+0

Это хороший способ проиллюстрировать ситуацию! –

Смежные вопросы