Last active
December 18, 2015 14:48
-
-
Save leppie/f035f71d080140f3ffcb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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