I wrote a program that allow two classes to "fight". For whatever reason C# always wins. What's wrong with VB.NET?

C#vb.netCompiler ConstructionInitialization

C# Problem Overview


I wrote a program that allow two classes to "fight". For whatever reason C# always wins. What's wrong with 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");
    }

Here are the players: Player A in C#:

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

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

Player B in 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

And here is a base class.

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

    public abstract int GetPower { get; }

    protected Player()
    {
        Power = GetPower;
    }
}

C# Solutions


Solution 1 - C#

The issue here is that VB is calling the base constructor before setting its field value. So the base Player class stores zero.

.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

Solution 2 - C#

Promoting my comments to an answer:

Me:

>Try writing each "power" to the console as well

Prankster:

>C#: 100 VB.NET: 0

Me:

>As I suspected. Looks like VB.Net is calling the Base constructor before the inherited constructor, and therefore VB's desiredPower variable is still 0, whereas C# does it in reverse (remember, literal initialization happens at the end of the constructor).

Update:
I wanted to find some documentation on the behavior (otherwise you're looking at behavior that might change out from under you with any new .Net release). From the link:

>The constructor of the derived class implicitly calls the constructor for the base class

and

>Base class objects are always constructed before any deriving class. Thus the constructor for the base class is executed before the constructor of the derived class.

Those are on the same page and would seem to be mutually exclusive, but I take it to mean the derived class constructor is invoked first, but it is assumed to itself invoke the base constructor before doing any other work. Therefore it's not constructor order that important, but the manner in which literals are initialized.

I also found this reference, which clearly says that the order is derived instance fields, then base constructor, then derived constructor.

Solution 3 - C#

By the time the constructor on B completes, both players will have a theoretical value of 100 in their private members.

However because of the superior internals of C#, the CLI generally considers integers and other primitive values values compiled from that language to be higher, and those from VB.NET to be lower, even when they contain the same bits.

Solution 4 - C#

This happens because C# first initialize class fields, and than call base constructors. VB instead does the opposite, so when in VB you assign your value to Power, private field is not yet initialized and its value is 0.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPranksterView Question on Stackoverflow
Solution 1 - C#Jb EvainView Answer on Stackoverflow
Solution 2 - C#Joel CoehoornView Answer on Stackoverflow
Solution 3 - C#James OrrView Answer on Stackoverflow
Solution 4 - C#Andrea ParodiView Answer on Stackoverflow