Я написал программу, которая позволяет двум классам "сражаться". По какой-то причине С# всегда выигрывает. Что случилось с VB.NET?

Я написал программу, которая позволяет двум классам "сражаться". По какой-то причине С# всегда выигрывает. Что не так с VB.NET?

   static void Main(string[] args)
    {
        Player a = new A();
        Player b = new B();

        if (a.Power > b.Power)
            Console.WriteLine("C# won");
        else if (a.Power < b.Power)
            Console.WriteLine("VB won");
        else
            Console.WriteLine("Tie");
    }

Вот игроки: Игрок A в С#:

public class A : Player
{
    private int desiredPower = 100;

    public override int GetPower
    {
        get { return desiredPower; }
    }
}

Игрок B в VB.NET:

Public Class B
   Inherits Player

   Dim desiredPower As Integer = 100

   Public Overrides ReadOnly Property GetPower() As Integer
       Get
          Return desiredPower
       End Get
   End Property
 End Class

И вот базовый класс.

public abstract class Player
{
    public int Power { get; private set; }

    public abstract int GetPower { get; }

    protected Player()
    {
        Power = GetPower;
    }
}

Ответ 1

Проблема здесь в том, что VB вызывает базовый конструктор, прежде чем устанавливать его значение поля. Таким образом, базовый класс Player сохраняет ноль.

.method public specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [base]Player::.ctor()
  IL_0006:  ldarg.0
  IL_0007:  ldc.i4.s   100
  IL_0009:  stfld      int32 B::desiredPower
  IL_000e:  ret
} // end of method B::.ctor

Ответ 2

Поощрение моих комментариев к ответу:

Me:

Попробуйте написать каждую "мощность" на консоли, а

Prankster:

С#: 100 VB.NET: 0

Me:

Как я и подозревал. Похоже, что VB.Net вызывает конструктор Base перед наследуемым конструктором, и поэтому переменная VB wishPower по-прежнему равна 0, тогда как С# делает это в обратном порядке (помните, что буквальная инициализация происходит в конце конструктора).

Update:
Я хотел найти некоторую документацию о поведении (в противном случае вы смотрите на поведение, которое может измениться из-под вас с любым новым выпуском .Net). По ссылке:

Конструктор производного класса неявно вызывает конструктор для базового класса

и

Объекты базового класса всегда создаются перед любым производным классом. Таким образом, конструктор базового класса выполняется перед конструктором производного класса.

Те, что находятся на одной странице и кажутся взаимоисключающими, но я полагаю, что это означает, что сначала вызывается конструктор производного класса, но предполагается, что он сам вызывает базовый конструктор, прежде чем выполнять какую-либо другую работу. Поэтому он не создает порядок, важный, но способ инициализации литералов.

Я также нашел эту ссылку, в которой четко сказано, что порядок - это производные экземпляры, затем базовый конструктор, а затем производный конструктор.

Ответ 3

К моменту завершения конструктора на B оба игрока будут иметь теоретическое значение 100 в своих частных членах.

Однако из-за превосходных внутренних элементов С# CLI обычно рассматривает целые числа и другие значения примитивных значений, скомпилированные с этого языка, чтобы быть выше, а из VB.NET - ниже, даже если они содержат одни и те же биты.

Ответ 4

Это происходит потому, что С# сначала инициализирует поля класса, а не конструкторы базовых вызовов. VB вместо этого делает обратное, поэтому, когда в VB вы назначаете свое значение Power, частное поле еще не инициализировано, а его значение равно 0.