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