private static Type GetDispatcher(Type dtype) {
// If a dispatcher type for the given delegate type has already
// been generated, get it from the cache. The cache maps delegate
// types to generated dispatcher types. A possible optimization
// for the future would be to generate dispatcher types based on
// unique signatures rather than delegate types, since multiple
// delegate types with the same sig could use the same dispatcher.
Object item = cache[dtype];
if (item != null) {
return (Type)item;
}
string name = "__" + dtype.FullName + "Dispatcher";
name = name.Replace('.', '_');
name = name.Replace('+', '_');
TypeBuilder tb = CodeGenerator.DefineType(name, basetype);
// Generate a constructor for the generated type that calls the
// appropriate constructor of the Dispatcher base type.
MethodAttributes ma = MethodAttributes.Public |
MethodAttributes.HideBySig |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName;
CallingConventions cc = CallingConventions.Standard;
Type[] args = {ptrtype, typetype};
ConstructorBuilder cb = tb.DefineConstructor(ma, cc, args);
ConstructorInfo ci = basetype.GetConstructor(args);
ILGenerator il = cb.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Call, ci);
il.Emit(OpCodes.Ret);
// Method generation: we generate a method named "Invoke" on the
// dispatcher type, whose signature matches the delegate type for
// which it is generated. The method body simply packages the
// arguments and hands them to the Dispatch() method, which deals
// with converting the arguments, calling the Python method and
// converting the result of the call.
MethodInfo method = dtype.GetMethod("Invoke");
ParameterInfo[] pi = method.GetParameters();
Type[] signature = new Type[pi.Length];
for (int i = 0; i < pi.Length; i++) {
signature[i] = pi[i].ParameterType;
}
MethodBuilder mb = tb.DefineMethod(
"Invoke",
MethodAttributes.Public,
method.ReturnType,
signature
);
ConstructorInfo ctor = listtype.GetConstructor(Type.EmptyTypes);
MethodInfo dispatch = basetype.GetMethod("Dispatch");
MethodInfo add = listtype.GetMethod("Add");
il = mb.GetILGenerator();
il.DeclareLocal(listtype);
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_0);
for (int c = 0; c < signature.Length; c++) {
Type t = signature[c];
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldarg_S, (byte)(c + 1));
if (t.IsValueType) {
il.Emit(OpCodes.Box, t);
}
il.Emit(OpCodes.Callvirt, add);
il.Emit(OpCodes.Pop);
}
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Call, dispatch);
if (method.ReturnType == voidtype) {
il.Emit(OpCodes.Pop);
}
il.Emit(OpCodes.Ret);
Type disp = tb.CreateType();
cache[dtype] = disp;
return disp;
}