源代码:https ://www.pastefile.com/4mzhyg
我正在尝试创建格式委托:
public delegate TReturn MethodCallerR<TTarget, TReturn>(ref TTarget target, object[] args);
/// <summary>
/// Generates a strongly-typed open-instance delegate to invoke the specified method
/// </summary>
public static MethodCallerR<TTarget, TReturn> DelegateForCallR<TTarget, TReturn>(this MethodInfo method) {
int key = GetKey<TTarget, TReturn>(method, kMethodCallerName);
Delegate result;
if (cache.TryGetValue(key, out result))
return (MethodCallerR<TTarget, TReturn>)result;
return GenDelegateForMember<MethodCallerR<TTarget, TReturn>, MethodInfo>(
method, key, kMethodCallerName, GenMethodInvocationR<TTarget>,
typeof(TReturn), typeof(TTarget).MakeByRefType(), typeof(object[]));
}
弱类型函数:
public static MethodCallerR<object, object> DelegateForCallR(this MethodInfo method) {
return DelegateForCallR<object, object>(method);
}
委托创建者:
static TDelegate GenDelegateForMember<TDelegate, TMember>(TMember member, int key, string dynMethodName,
Action<TMember> generator, Type returnType, params Type[] paramTypes)
where TMember : MemberInfo
where TDelegate : class {
var dynMethod = new DynamicMethod(dynMethodName, returnType, paramTypes, true);
emit.il = dynMethod.GetILGenerator();
generator(member);
var result = dynMethod.CreateDelegate(typeof(TDelegate));
cache[key] = result;
return (TDelegate)(object)result;
}
和 IL 代码生成器:
static void GenMethodInvocationR<TTarget>(MethodInfo method) {
var weaklyTyped = typeof(TTarget) == typeof(object);
// push arguments in order to call method
var prams = method.GetParameters();
var imax = prams.Length;
for (int i = 0; i < imax; i++) {
emit.ldarg1() // stack<= paramsValuesArray[] //push array
.ldc_i4(i) // stack<= index push(index)
.ldelem_ref(); // stack[top]<=paramsValuesArray[i]
var param = prams[i];
var dataType = param.ParameterType;
if (dataType.IsByRef)
dataType = dataType.GetElementType();
emit.unbox_any(dataType);
emit.declocal(dataType);
emit.stloc(i);
}
if (!method.IsStatic)
{
var targetType = weaklyTyped ? method.DeclaringType : typeof(TTarget);
emit.ldarg0(); //stack[top]=target;
emit.ldind_ref();//stack[top]=ref target;
if (weaklyTyped)
emit.unbox_any(targetType); //stack[top]=(TargetType)target;
}
//load parms from local 'list' to evaluation 'steak'
for (int i = 0; i < imax; i++) {
var param = prams[i];
emit.ifbyref_ldloca_else_ldloc(i, param.ParameterType);
}
// perform the correct call (pushes the result)
emit.callorvirt(method);
//check of ref and out params and
for (int i = 0; i < prams.Length; i++) {
var paramType = prams[i].ParameterType;
if (paramType.IsByRef)
{
var byRefType = paramType.GetElementType();
emit.ldarg1() // stack<= paramsValuesArray[]
.ldc_i4(i) // stack<= i //push(index)
.ldloc(i); // stack<= list[i] //push local list element at 'i' on steak
if (byRefType.IsValueType)
emit.box(byRefType); // if ex. stack[top] =(object)stack[top]
emit.stelem_ref(); // // paramsValuesArray[i]= pop(stack[top]);
}
}
if (method.ReturnType == typeof(void))
emit.ldnull();
else if (weaklyTyped)
emit.ifvaluetype_box(method.ReturnType);
emit.ret();
}
我正在使用的 stuct 示例是 Vector3 和 Set 方法:
public struct Vector3{
public float x;
public float y;
public float z;
public Vector3(float x,float y,float z){
this.x=x;
this.y=y;
this.z=z;
}
public void Set(float x,float y,float z){
this.x=x;
this.y=y;
this.z=z;
}
}
所以我在做:
object vector3Obj=new Vector3(4,5,6);
MethodInfo method=typeof(Vector3).GetMethod("Set");
MethodCallerR<object,object> m = methodInfo.DelegateForCallR();
m(ref vector3Obj,new object[]{1f,2f,3f});
Console.Write(vector3.x);
永远不要到达正在执行的委托,但是当它调用 Delegate.CreateDelegate 时它会崩溃:
见行:dynMethod.CreateDelegate(typeof(TDelegate));
有错误:
InvalidProgramException: Invalid IL code in (wrapper dynamic-method) object:MC<> (object&,object[]): IL_004f: call 0x00000009 裁判实际 IL 代码在 emit.call(method) 处有错误,但是当我使用辅助函数时:
FastReflection.GenDebugAssembly<object>("my.dll",null,null,methodInfo,vector3Obj.GetType(),new Type[]{typeof(float),typeof(float),typeof(float)});
这将生成 my.dll 并使用 ILSpy 打开我可以看到来自相同 IL 代码的方法生成得很好。
public static object MethodCallerR(ref object ptr, object[] array)
{
float num = (float)array[0];
float num2 = (float)array[1];
float num3 = (float)array[2];
((Vector3)ptr).Set(num, num2, num3);
return null;
}