Skip to content

Instantly share code, notes, and snippets.

@leppie
Last active December 18, 2015 14:48
Show Gist options
  • Save leppie/f035f71d080140f3ffcb to your computer and use it in GitHub Desktop.
Save leppie/f035f71d080140f3ffcb to your computer and use it in GitHub Desktop.
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
public class App
{
static readonly Type[][] paramTypesArray = new Type[][] {
new Type[] {},
new Type[] { typeof(object) },
new Type[] { typeof(object), typeof(object) },
new Type[] { typeof(object), typeof(object), typeof(object) },
new Type[] { typeof(object), typeof(object), typeof(object), typeof(object) },
new Type[] { typeof(object), typeof(object), typeof(object), typeof(object), typeof(object) },
};
delegate object CallTarget0();
delegate object CallTarget1(object arg0);
delegate object CallTarget2(object arg0, object arg1);
delegate object CallTarget3(object arg0, object arg1, object arg2);
delegate object CallTarget4(object arg0, object arg1, object arg2, object arg3);
delegate object CallTarget5(object arg0, object arg1, object arg2, object arg3, object arg4);
static readonly Type[] callTargets = new Type[] {
typeof(CallTarget0),
typeof(CallTarget1),
typeof(CallTarget2),
typeof(CallTarget3),
typeof(CallTarget4),
typeof(CallTarget5),
};
static IEnumerable<Type> GetArgTypes(Delegate d)
{
if (d.Target != null)
{
yield return d.Target.GetType();
}
foreach (var p in d.Method.GetParameters())
{
yield return p.ParameterType;
}
}
static IEnumerable<Type> GetBoxedArgs(Delegate d)
{
if (d.Target != null)
{
yield return typeof(object);
}
foreach (var p in d.Method.GetParameters())
{
yield return typeof(object);
}
}
static Delegate Wrap(Delegate del)
{
var method = del.Method;
var pl = method.GetParameters().Length;
var param = GetArgTypes(del).ToArray();
var boxpar = GetBoxedArgs(del).ToArray();
var dynmeth = new DynamicMethod("", typeof(object), boxpar, true);
var gen = dynmeth.GetILGenerator();
for (int i = 0; i < param.Length; i++)
{
gen.Emit(OpCodes.Ldarg_S, (byte)i);
gen.Emit(OpCodes.Unbox_Any, param[i]);
}
gen.Emit(OpCodes.Call, method);
if (method.ReturnType.IsValueType) gen.Emit(OpCodes.Box, method.ReturnType);
gen.Emit(OpCodes.Ret);
var outType = callTargets[pl];
if (del.Target != null)
{
return dynmeth.CreateDelegate(outType, del.Target);
}
else
{
return dynmeth.CreateDelegate(outType);
}
}
static int op(int a, int b) { return a * b; }
static void Main()
{
// this works
var g1 = (CallTarget2)Wrap((Func<int, int, int>)op);
Console.WriteLine(g1(3, 4));
// this does not
Func<int, int, int> f = (a, b) => a * b;
Console.WriteLine(f(3, 4));
var g2 = (CallTarget2)Wrap(f);
Console.WriteLine(g2(3, 4));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment