可悲的是,@kvb 似乎是正确的。也就是说,您想要完成“GetMethodToken”的艰苦工作的方法似乎确实采用了方法库。因此,如果您不反对表达式树,您可以制作自己的方法版本。这是我最好的猜测(减去参数验证)我还没有在每种情况下都对其进行全面测试,但是您现在可以使用 func 作为调用 vararg 方法或 vararg ctor 的方法。
::
var ilgen = Expression.Parameter(typeof(ILGenerator));
var code = Expression.Parameter(typeof(OpCode));
var method = Expression.Parameter(typeof(MethodBase));
var opttypes = Expression.Parameter(typeof(Type[]));
var stackchange = Expression.Variable(typeof(int));
var tok = Expression.Variable(typeof(int));
var paramTypes= Expression.Variable(typeof(Type[]));
var expr = Expression.Lambda<Action<ILGenerator, OpCode, MethodBase, Type[]>>(Expression.Block(
new[]{stackchange,tok,paramTypes},
Expression.Assign(stackchange, Expression.Constant(0)),
Expression.Assign(tok,
Expression.Call(ilgen,
typeof(ILGenerator)
.GetMethod("GetMethodToken", BindingFlags.NonPublic | BindingFlags.Instance),
method,
opttypes,
Expression.Constant(false)
)
),
Expression.Call(ilgen, typeof(ILGenerator).GetMethod("EnsureCapacity", BindingFlags.Instance | BindingFlags.NonPublic), Expression.Constant(7)),
Expression.Call(ilgen, typeof(ILGenerator).GetMethod("InternalEmit",BindingFlags.Instance|BindingFlags.NonPublic), code),
Expression.IfThen(
Expression.AndAlso(
Expression.Not(
Expression.Property(method, "IsConstructor")
),
Expression.Equal(
Expression.Property(
Expression.Convert(method, typeof(MethodInfo)),
"ReturnType"
),
Expression.Constant(typeof(void))
)
),
Expression.PostIncrementAssign(stackchange)
),
Expression.Assign(paramTypes, Expression.Call(method,
typeof(MethodInfo)
.GetMethod("GetParameterTypes", BindingFlags.NonPublic | BindingFlags.Instance)
)
),
Expression.IfThen(
Expression.AndAlso(
Expression.AndAlso(
Expression.TypeIs(method, Type.GetType("System.Reflection.Emit.SymbolMethod")),
Expression.Property(method, "IsStatic")
),
Expression.Equal(
code,
Expression.Constant(OpCodes.Newobj, typeof(OpCode))
)
),
Expression.PostDecrementAssign(stackchange)
),
Expression.IfThen(Expression.NotEqual(opttypes, Expression.Constant(null)),
Expression.SubtractAssign(stackchange, Expression.ArrayLength(opttypes))
),
Expression.Call(ilgen, typeof(ILGenerator).GetMethod("UpdateStackSize", BindingFlags.NonPublic | BindingFlags.Instance), code, stackchange),
Expression.Call(ilgen, typeof(ILGenerator).GetMethod("RecordTokenFixup", BindingFlags.NonPublic | BindingFlags.Instance)),
Expression.Call(ilgen, typeof(ILGenerator).GetMethod("PutInteger4", BindingFlags.NonPublic | BindingFlags.Instance),tok)
),
ilgen, code, method, opttypes);
var func = expr.Compile();
从这里你可以像这样在你的类型上使用它:
public class VarArgTest
{
public int CountOfArgs;
public VarArgTest(string test, __arglist)
{
ArgIterator args = new ArgIterator(__arglist);
CountOfArgs = args.GetRemainingCount();
}
}
//然后在方法中创建类
var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Foo"), AssemblyBuilderAccess.RunAndSave);
var mb = ab.DefineDynamicModule(ab.GetName().Name, ab.GetName().Name + ".dll", true);
var tb = mb.DefineType("Foo", TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.Public, typeof(VarArgTest));
var ctor = tb.DefineConstructor(MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,CallingConventions.HasThis,Type.EmptyTypes);
var il =ctor.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, "foo");
il.Emit(OpCodes.Ldstr, "one");
il.Emit(OpCodes.Ldc_I4_2);
func(il, OpCodes.Call, typeof(VarArgTest).GetConstructors()[0], new[] { typeof(string), typeof(int) });
il.Emit(OpCodes.Ret);
var v=Activator.CreateInstance(tb.CreateType());
Console.WriteLine((v as VarArgTest).CountOfArgs);
打印 2。