Skip to content

Instantly share code, notes, and snippets.

@weltkante
Created October 30, 2017 10:42
Show Gist options
  • Save weltkante/94652de66940d494cdcf61e3a62a4b0f to your computer and use it in GitHub Desktop.
Save weltkante/94652de66940d494cdcf61e3a62a4b0f to your computer and use it in GitHub Desktop.
test ref-return and dynamic code generation
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace TestProgram
{
delegate ref int GetRefIntoArrayDelegate(int[] array, int index);
class Program
{
static int[] _values = new int[8];
static void Main()
{
Console.WriteLine("Testing C# implementation");
Test1(); // calls C# implementation directly
Console.WriteLine("Testing C# implementation via delegate");
Test2(() => GetRefIntoArrayImpl); // uses C# implementation via delegate
Console.WriteLine("Testing dynamic assembly");
Test2(() => CreateDynamicAssemblyImpl()); // uses dynamic assembly delegate
Console.WriteLine("Testing dynamic method");
Test2(() => CreateDynamicMethodImpl()); // uses dynamic method delegate
}
static void Test1()
{
try
{
InitValues();
ref int p = ref GetRefIntoArrayImpl(_values, 4);
p = 40;
PrintValues();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
}
static void Test2(Func<GetRefIntoArrayDelegate> factory)
{
try
{
var f = factory();
InitValues();
ref int p = ref f(_values, 4);
p = 40;
PrintValues();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
}
}
static void InitValues()
{
for (int i = 0; i < _values.Length; i++)
_values[i] = i;
}
static void PrintValues()
{
Console.WriteLine(string.Join(", ", _values));
}
static ref int GetRefIntoArrayImpl(int[] array, int index)
{
/*
.method private hidebysig static
int32& GetRefIntoArrayImpl (
int32[] 'array',
int32 index
) cil managed
{
// Method begins at RVA 0x2149
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldelema [System.Runtime]System.Int32
IL_0007: ret
} // end of method Program::GetRefIntoArrayImpl
*/
return ref array[index];
}
static GetRefIntoArrayDelegate CreateDynamicAssemblyImpl()
{
var name = new AssemblyName("GeneratedCodeContainer");
var assembly = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndCollect);
var module = assembly.DefineDynamicModule(name.Name);
var type = module.DefineType("GeneratedMethodContainer", TypeAttributes.Public);
var method = type.DefineMethod("GetRefIntoArray_DynamicAssemblyImpl", MethodAttributes.Public | MethodAttributes.Static, typeof(int).MakeByRefType(), new[] { typeof(int[]), typeof(int) });
var code = method.GetILGenerator();
code.Emit(OpCodes.Ldarg_0);
code.Emit(OpCodes.Ldarg_1);
code.Emit(OpCodes.Ldelema, typeof(int));
code.Emit(OpCodes.Ret);
return (GetRefIntoArrayDelegate)type.CreateType().GetMethod(method.Name).CreateDelegate(typeof(GetRefIntoArrayDelegate));
}
static GetRefIntoArrayDelegate CreateDynamicMethodImpl()
{
var method = new DynamicMethod("GetRefIntoArray_DynamicMethodImpl", typeof(int).MakeByRefType(), new[] { typeof(int[]), typeof(int) });
var code = method.GetILGenerator();
code.Emit(OpCodes.Ldarg_0);
code.Emit(OpCodes.Ldarg_1);
code.Emit(OpCodes.Ldelema, typeof(int));
code.Emit(OpCodes.Ret);
return (GetRefIntoArrayDelegate)method.CreateDelegate(typeof(GetRefIntoArrayDelegate));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment