3

I was wondering: how is the C# array indexer implemented? You can index a C# array with basically every integer value from ulong to sbyte, does the internal implementation simply casts to a common type every time?

To be clear will this:

ulong i = 10;
var o = myArray[i];

be translated into something like:

ulong i =10;
var o = myArray[(int /*or whatver is the default type used*/)i];

?

5
  • 3
    Enjoy Commented Oct 18, 2018 at 10:31
  • 2
    good luck finding that in the source code. Commented Oct 18, 2018 at 10:32
  • 2
    @Zohar: You should probably link to the implementation of the IL instructions in the JIT, as that's what's happening there, and not a method call on System.Array. Commented Oct 18, 2018 at 10:40
  • Note that the check is not actually alwas executed. The JiT and general IL optimsiations can really help keeping the load low: blogs.msdn.microsoft.com/clrcodegeneration/2009/08/13/… Commented Oct 18, 2018 at 10:41
  • Thanks everyone! Commented Oct 18, 2018 at 11:39

1 Answer 1

5

The type of an array indexer is integer, so yes, the value will be converted to int. You can verify this by examining the IL code. Given this example:

var myArray = new[]{ 1,2,3 };
ulong i = 10;
var o = myArray[i];

This will compile into:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       29 (0x1d)
  .maxstack  3
  .locals init ([0] int32[] myArray,
           [1] uint64 i,
           [2] int32 o)
  IL_0000:  nop
  IL_0001:  ldc.i4.3
  IL_0002:  newarr     [mscorlib]System.Int32
  IL_0007:  dup
  IL_0008:  ldtoken    field valuetype '<PrivateImplementationDetails>'/'__StaticArrayInitTypeSize=12' '<PrivateImplementationDetails>'::E429CCA3F703A39CC5954A6572FEC9086135B34E
  IL_000d:  call       void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array,
                                                                                                      valuetype [mscorlib]System.RuntimeFieldHandle)
  IL_0012:  stloc.0
  IL_0013:  ldc.i4.s   10
  IL_0015:  conv.i8
  IL_0016:  stloc.1
  IL_0017:  ldloc.0
  IL_0018:  ldloc.1
  IL_0019:  conv.ovf.i.un
  IL_001a:  ldelem.i4
  IL_001b:  stloc.2
  IL_001c:  ret
} // end of method Program::Main

The conversion happens at IL_0019 with conv.ovf.i.un instruction.

Converts the unsigned value on top of the evaluation stack to signed native int, throwing OverflowException on overflow.

Sign up to request clarification or add additional context in comments.

3 Comments

An easy way to show IL for your code is SharpLab.io - for the curious reader of this answer.
Thank you! I did try SharpLab.io before asking but I still can't understand IL very well, this is why I've asked the question :)
I know that this answer will stay the same but if you want to 'proof' this kind of question with IL you will need to repeat this with forced x64 and x32 platforms, optimization on/off, ... . You didn't even mention your settings. I always prefer a specification.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.