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

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

45 голосов
/ 03 апреля 2009

Проблема здесь в том, что 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
16 голосов
/ 03 апреля 2009

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

Я:

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

Prankster:

C #: 100 VB.NET: 0

Я:

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

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

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

и

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

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

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

1 голос
/ 04 августа 2010

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

1 голос
/ 03 апреля 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...