понимание вложенных родовых классов в C # с викториной

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

Код:

public class A
{
    public T1 a;

    public class B : A
    {
        public T1 b;

        public class C : B
        {
            public T1 c;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        A.B.C o = new A.B.C();

        Console.WriteLine(o.a.GetType());
        Console.WriteLine(o.b.GetType());
        Console.WriteLine(o.c.GetType());

        Console.ReadKey();
    }
}

Выход:

System.Boolean
System.Char
System.Int32

Correct me if I'm wrong, but I understand that o.a is of type bool because C inherits from B and B inherits from A. 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).

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

60
nl ja de
Интересный, но полный перебор для чего-то практического. Я предполагаю, что это скорее академическая, чем работа?
добавлено автор JGilmartin, источник
Интересный, но полный перебор для чего-то практического. Я предполагаю, что это скорее академическая, чем работа?
добавлено автор JGilmartin, источник
добавление четвертого класса показывает, что он работает как стек
добавлено автор Nahum, источник
добавление четвертого класса показывает, что он работает как стек
добавлено автор Nahum, источник
Я рад, что не поддерживаю код в вашей компании.
добавлено автор Default, источник
@Erix кто-то должен был понять это на основе чего-то, и я предполагаю, что это произошло из какого-то производственного кода. А также нет, я не слишком увлекаюсь тем, что я не вижу практического использования ..
добавлено автор Default, источник
@Erix кто-то должен был понять это на основе чего-то, и я предполагаю, что это произошло из какого-то производственного кода. А также нет, я не слишком увлекаюсь тем, что я не вижу практического использования ..
добавлено автор Default, источник
Где поступить: public class B : A дает ожидаемые результаты, интересные.
добавлено автор MBen, источник
Где поступить: public class B : A дает ожидаемые результаты, интересные.
добавлено автор MBen, источник
@Default Почему? Потому что им нравится викторины друг другу по странному C# -коду?
добавлено автор Erix, источник
@Default Почему? Потому что им нравится викторины друг другу по странному C# -коду?
добавлено автор Erix, источник
@default не то, что викторины в первую очередь?
добавлено автор dmaij, источник
@default не то, что викторины в первую очередь?
добавлено автор dmaij, источник

4 ответы

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

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

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

Немного более простая версия находится в моем блоге.

http://blogs.msdn.com/ б/ericlippert/архив/2007/07/27/Ан-наследование головоломка неполного one.aspx

Решение моей версии находится здесь:

http://blogs.msdn.com/ б/ericlippert/архив/2007/07/30/Ан-наследование головоломка неполного 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 . Эта головоломка создает вложенные общие типы таким образом, что одно и то же объявление может быть названо как с помощью «внешних», так и «базовых» путей поиска, но имеет значения different в каждом из-за общей конструкции.

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

40
добавлено

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

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

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

Немного более простая версия находится в моем блоге.

http://blogs.msdn.com/ б/ericlippert/архив/2007/07/27/Ан-наследование головоломка неполного one.aspx

Решение моей версии находится здесь:

http://blogs.msdn.com/ б/ericlippert/архив/2007/07/30/Ан-наследование головоломка неполного 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 . Эта головоломка создает вложенные общие типы таким образом, что одно и то же объявление может быть названо как с помощью «внешних», так и «базовых» путей поиска, но имеет значения different в каждом из-за общей конструкции.

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

40
добавлено

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

in o.b.GetType() b is the member of the surrounding class which is instantiated as B which inherits from A 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;
        }
    }
}

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

8
добавлено
Это хороший способ проиллюстрировать ситуацию!
добавлено автор Eric Lippert, источник
Тогда почему o.c не bool? Потому что C наследует от B , который в свою очередь наследует от A ..
добавлено автор Memet Olsen, источник
Да, что вводит в заблуждение, разница между наследованием и охватывающими типами. C заключен в B , но наследуется от B
добавлено автор CubeSchrauber, источник

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

in o.b.GetType() b is the member of the surrounding class which is instantiated as B which inherits from A 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;
        }
    }
}

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

8
добавлено
Это хороший способ проиллюстрировать ситуацию!
добавлено автор Eric Lippert, источник
Тогда почему o.c не bool? Потому что C наследует от B , который в свою очередь наследует от A ..
добавлено автор Memet Olsen, источник
Да, что вводит в заблуждение, разница между наследованием и охватывающими типами. C заключен в B , но наследуется от B
добавлено автор CubeSchrauber, источник
Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot