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

Я написал программу, позволяющую двум классам "драться". По какой-то причине C# всегда побеждает. Что не так с 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 в C#:

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

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

Игрок Б в 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;
    }
}

4 ответа

Решение

Проблема здесь в том, что 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

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

Мне:

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

Шутник:

C#: 100 VB.NET: 0

Мне:

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

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

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

а также

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

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

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

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

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

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

Другие вопросы по тегам