rendered paste bodyDelegate^ SMBinder::BindToDelegate(SMScript^ script, Type^ delegateType, SMFunction^ func){ if (delegateType->IsAbstract)//can't instanciate abstract classes return nullptr; MethodInfo^ target = delegateType->GetMethod("Invoke"); MethodInfo^ wrapper = func->GetType()->GetMethod("Invoke", BindingFlags::Public | BindingFlags::Instance); array<ParameterInfo^>^ params = target->GetParameters(); array<Type^>^ sigArgs = gcnew array<Type^>(params->Length + 1); sigArgs[0] = array<Object^>::typeid; for (int i = 1; i < sigArgs->Length; i++) sigArgs[i] = params[i - 1]->ParameterType; DynamicMethod^ method = gcnew DynamicMethod("SomeMethod", target->ReturnType, sigArgs, true); ILGenerator^ methodIL = method->GetILGenerator(); LocalBuilder^ consts = methodIL->DeclareLocal(array<Object^>::typeid); LocalBuilder^ args = methodIL->DeclareLocal(array<Object^>::typeid); LocalBuilder^ instance = methodIL->DeclareLocal(SMFunction::typeid); LocalBuilder^ returnType = methodIL->DeclareLocal(Type::typeid); LocalBuilder^ returnValue = methodIL->DeclareLocal(Object::typeid); methodIL->Emit(OpCodes::Ldarg_0); methodIL->Emit(OpCodes::Stloc_S, consts); //instance methodIL->Emit(OpCodes::Ldloc_S, consts); methodIL->Emit(OpCodes::Ldc_I4_S, 0); methodIL->Emit(OpCodes::Ldelem_Ref); methodIL->Emit(OpCodes::Castclass, SMFunction::typeid); methodIL->Emit(OpCodes::Stloc_S, instance); methodIL->Emit(OpCodes::Ldc_I4_S, sigArgs->Length - 1); methodIL->Emit(OpCodes::Newarr, Object::typeid); methodIL->Emit(OpCodes::Stloc_S, args); for (int i = 1; i < sigArgs->Length; i++) { methodIL->Emit(OpCodes::Ldloc_S, args); methodIL->Emit(OpCodes::Ldc_I4_S, i - 1); methodIL->Emit(OpCodes::Ldarg_S, i); methodIL->Emit(OpCodes::Box, sigArgs[i]); methodIL->Emit(OpCodes::Stelem_Ref); } methodIL->Emit(OpCodes::Ldloc_S, instance); methodIL->Emit(OpCodes::Ldloc_S, args); methodIL->Emit(OpCodes::Callvirt, wrapper); methodIL->Emit(OpCodes::Stloc_S, returnValue); //if the current delegate has a return type //we want to convert the return value and unbox it if (target->ReturnType != void::typeid) { MethodInfo^ convert = (Interop::typeid)->GetMethod("ChangeType"); LocalBuilder^ scr = methodIL->DeclareLocal(SMScript::typeid); //script methodIL->Emit(OpCodes::Ldloc_S, consts); methodIL->Emit(OpCodes::Ldc_I4_S, 1); methodIL->Emit(OpCodes::Ldelem_Ref); methodIL->Emit(OpCodes::Castclass, SMScript::typeid); methodIL->Emit(OpCodes::Stloc_S, scr); Label ELSE = methodIL->DefineLabel(); Label END = methodIL->DefineLabel(); //load our return type metadata token methodIL->Emit(OpCodes::Ldtoken, target->ReturnType); methodIL->Emit(OpCodes::Call, Type::typeid->GetMethod("GetTypeFromHandle")); methodIL->Emit(OpCodes::Stloc_S, returnType); methodIL->Emit(OpCodes::Ldloc_S, scr); methodIL->Emit(OpCodes::Ldloca_S, returnValue); methodIL->Emit(OpCodes::Ldloc_S, returnType); methodIL->Emit(OpCodes::Call, convert); methodIL->Emit(OpCodes::Brfalse_S, ELSE); methodIL->Emit(OpCodes::Br_S, END); methodIL->MarkLabel(ELSE); LocalBuilder^ local = methodIL->DeclareLocal(target->ReturnType); methodIL->Emit(OpCodes::Ldloca, local); methodIL->Emit(OpCodes::Initobj, local->LocalType); methodIL->Emit(OpCodes::Ldloc_S, local); methodIL->Emit(OpCodes::Box, Object::typeid); methodIL->Emit(OpCodes::Stloc_S, returnValue); methodIL->MarkLabel(END); methodIL->Emit(OpCodes::Ldloc_S, returnValue); methodIL->Emit(OpCodes::Unbox_Any, target->ReturnType); } methodIL->Emit(OpCodes::Ret); return method->CreateDelegate(delegateType, gcnew array<Object^>{ func, script });}