Set Value on Array: Performance Test

 //
// Please refer to https://blogs.msdn.com/haibo_luo "Late-bound array operations" post
//
// To compile this file, you need download Vance's CodeTimers class 
// @ https://blogs.msdn.com/vancem/archive/2006/09/21/765648.aspx
//
// THIS CODE IS PROVIDED "AS IS", WITH NO WARRANTIES INTENDED OR IMPLIED. USE AT YOUR OWN RISK
//

using System;
using System.Collections.Generic;
using System.Text;
using PerformanceMeasurement;
using System.Reflection.Emit;
using System.Reflection;

namespace ArraySetValuePerfMeasurement {
    delegate void MySetValue(Array array, int index, int value);

    class Program {
        static void Main(string[] args) {
            // Measure how long it takes to fetch all the keys exactly once
            MultiSampleCodeTimer timer = new MultiSampleCodeTimer(8, 1000000);
            Console.WriteLine("Data units of msec resolution = " + MultiSampleCodeTimer.ResolutionUsec.ToString("f6") + " usec");

            Array x = Array.CreateInstance(typeof(int), 10);

            // early-bind set
            int[] y = (int[])x;

            timer.Measure("Early-bound assignment                  ", delegate {
                y[0] = 100;
                y[1] = 200;
                y[2] = 300;
                y[3] = 400;
                y[4] = 500;
                y[5] = 600;
                y[6] = 700;
                y[7] = 800;
                y[8] = 900;
                y[9] = 1000;
            });

            timer.Measure("Late-bound set via Array.SetValue       ", delegate {
                x.SetValue(100, 0);
                x.SetValue(200, 1);
                x.SetValue(300, 2);
                x.SetValue(400, 3);
                x.SetValue(500, 4);
                x.SetValue(600, 5);
                x.SetValue(700, 6);
                x.SetValue(800, 7);
                x.SetValue(900, 8);
                x.SetValue(1000, 9);
            });

            DynamicMethod dm = new DynamicMethod("SetValueByStelem", typeof(void),
                new Type[] { typeof(Array), typeof(int), typeof(int) }, typeof(Program));
            ILGenerator ilgen = dm.GetILGenerator();
            ilgen.Emit(OpCodes.Ldarg_0);
            ilgen.Emit(OpCodes.Castclass, x.GetType());
            ilgen.Emit(OpCodes.Ldarg_1); // index
            ilgen.Emit(OpCodes.Ldarg_2); // value
            ilgen.Emit(OpCodes.Stelem_I4);
            ilgen.Emit(OpCodes.Ret);
            MySetValue sv = (MySetValue)dm.CreateDelegate(typeof(MySetValue));

            timer.Measure("Late-bound set via DynamicMethod/Stelem ", delegate {
                sv(x, 0, 100);
                sv(x, 1, 200);
                sv(x, 2, 300);
                sv(x, 3, 400);
                sv(x, 4, 500);
                sv(x, 5, 600);
                sv(x, 6, 700);
                sv(x, 7, 800);
                sv(x, 8, 900);
                sv(x, 9, 1000);
            });

            MethodInfo mi = x.GetType().GetMethod("Set");
            timer.Measure("Late-bound set via Set MethodInfo.Invoke", delegate {
                mi.Invoke(x, new object[] { 0, 100 });
                mi.Invoke(x, new object[] { 1, 200 });
                mi.Invoke(x, new object[] { 2, 300 });
                mi.Invoke(x, new object[] { 3, 400 });
                mi.Invoke(x, new object[] { 4, 500 });
                mi.Invoke(x, new object[] { 5, 600 });
                mi.Invoke(x, new object[] { 6, 700 });
                mi.Invoke(x, new object[] { 7, 800 });
                mi.Invoke(x, new object[] { 8, 900 });
                mi.Invoke(x, new object[] { 9, 1000 });
            });

            dm = new DynamicMethod("SetValueBySet", typeof(void),
               new Type[] { typeof(Array), typeof(int), typeof(int) }, typeof(Program));

            ilgen = dm.GetILGenerator();
            ilgen.Emit(OpCodes.Ldarg_0);
            ilgen.Emit(OpCodes.Castclass, x.GetType());
            ilgen.Emit(OpCodes.Ldarg_1);
            ilgen.Emit(OpCodes.Ldarg_2);
            ilgen.Emit(OpCodes.Call, mi);
            ilgen.Emit(OpCodes.Ret);

            sv = (MySetValue)dm.CreateDelegate(typeof(MySetValue));

            timer.Measure("Late-bound set via DynamicMethod/Set    ", delegate {
                sv(x, 0, 100);
                sv(x, 1, 200);
                sv(x, 2, 300);
                sv(x, 3, 400);
                sv(x, 4, 500);
                sv(x, 5, 600);
                sv(x, 6, 700);
                sv(x, 7, 800);
                sv(x, 8, 900);
                sv(x, 9, 1000);
            });
        }
    }
}