Source code:https://www.pastefile.com/4mzhyg
I'm trying to create delegate of format:
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[]));
}
weak type function:
public static MethodCallerR<object, object> DelegateForCallR(this MethodInfo method) {
return DelegateForCallR<object, object>(method);
}
delegate creator:
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;
}
and IL code generator:
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();
}
Example for stuct I'm using is Vector3 with Set method:
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;
}
}
so I'm doing:
Vector3 vector3=new Vector3(4,5,6);
MethodInfo method=typeof(Vector3).GetMethod("Set");
MethodCallerR<object,object> m = methodInfo.DelegateForCallR();
m(ref vector3,new object[]{1f,2f,3f});
Console.Write(vector3.x);
Never get to the executing delegate, but it blows when it calls Delegate.CreateDelegate:
see line: dynMethod.CreateDelegate(typeof(TDelegate));
with error: InvalidProgramException: Invalid IL code in (wrapper dynamic-method) object:MC<> (object&,object[]): IL_004f: call 0x00000009 refereeing that actual IL code has error at emit.call(method), but when I use helper function:
FastReflection.GenDebugAssembly<object>("my.dll",null,null,methodInfo,this.__anyObject.GetType(),new Type[]{typeof(float),typeof(float),typeof(float)});
which will generate my.dll and open with ILSpy I can see that method from same IL code is generated just fine.
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;
}
Aucun commentaire:
Enregistrer un commentaire