Question

In debugging step through, Visual Studio 2013 shows BitConverter.IsLittleEndian is:

  1. false: When I hover mouse on BitConverter and see the value of BitConverter.IsLittleEndian and
  2. true: When I put it in a variable like var x = BitConverter.IsLittleEndian;

I assume BitConverter.IsLittleEndian should be already evaluated because I have called GetBytes on BitConverter so it's static constructor should be called at this point, right? What am I missing?

My code is this (I wanted to generate sequential Guid; rest is bytes of a long counter - at this version):

static Guid Id(long ticks, byte[] rest)
{
    var ticksBytes = BitConverter.GetBytes(ticks).PolishEndian();
    // var x = BitConverter.IsLittleEndian; // <- TESTED HERE
    int a = BitConverter.ToInt32(new byte[] { ticksBytes[4], ticksBytes[5], ticksBytes[6], ticksBytes[7] }.PolishEndian(), 0);
    short b = BitConverter.ToInt16(new byte[] { ticksBytes[2], ticksBytes[3] }.PolishEndian(), 0);
    short c = BitConverter.ToInt16(new byte[] { ticksBytes[0], ticksBytes[1] }.PolishEndian(), 0);

    return new Guid(a, b, c, rest.PolishEndian(true).ToArray());
}

static byte[] PolishEndian(this byte[] ba, bool reverse = false)
{
    var flag = reverse ? BitConverter.IsLittleEndian : !BitConverter.IsLittleEndian;

    if (flag) return ba.Reverse().ToArray();

    return ba;
}
Was it helpful?

Solution

Note that in this case IsLittleEndian is actually a field and not a property. That has an effect on how the EE is able to process the value.

I tried this out locally and this is the behavior I saw

First i stepped until the cursor hit the var ticksBytes line. At that point I observed that IsLittleEndian == false. This is actually expected at this point. The EE does not always need to force a static constructor to run in order to read fields. Hence it is just reading the value as is and because no other code for BitConverter has run the value is false

Immediately after stepping over that line I observe that IsLittleEndian == true. The CLR ran the static constructor in order to execute the GetBytes method and hence that set the field. The EE was then reading the set field.

Note that you can recreate this example with your own code. For example

static class Test { 
  static readonly bool example;

  static Test() { 
    example = true;
  }

  internal static void Go() { 
    // example == true 
  }
}

class Program { 

  static void Main() {
    // Test.example == false;
    Test.Go();  
  }
}

Earlier I mentioned that the EE didn't always need to execute a static constructor in order to read fields. One case where it often needs to is when reading static fields off of a generic type. The storage for a static field of a generic type isn't created essentially until the CLR instantiates an instance of the type. Hence in order to read a field off of a generic type which hasn't yet been used the EE will create an instance under the cover in order to force the CLR to read it. For example

static class Test<T>
{
    static readonly bool example = false;

    static Test()
    {
        example = true;
    }
}

If you add this to your program and then evaluate the following in the watch window

Test<int>.example

you will find that the value is true clearly indicating the cctor ran

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top