LuaInterface.CodeGeneration.GenerateDelegate C# (CSharp) Method

GenerateDelegate() private method

private GenerateDelegate ( Type delegateType ) : Type
delegateType System.Type
return System.Type
        private Type GenerateDelegate(Type delegateType)
        {
            string typeName;
            lock(this)
            {
                typeName = "LuaGeneratedClass" + luaClassNumber;
                luaClassNumber++;
            }
            // Define a public class in the assembly, called typeName
            TypeBuilder myType=newModule.DefineType(typeName,TypeAttributes.Public,delegateParent);

            // Defines the delegate method with the same signature as the
            // Invoke method of delegateType
            MethodInfo invokeMethod=delegateType.GetMethod("Invoke");
            ParameterInfo[] paramInfo=invokeMethod.GetParameters();
            Type[] paramTypes=new Type[paramInfo.Length];
            Type returnType=invokeMethod.ReturnType;

            // Counts out and ref params, for use later
            int nOutParams=0; int nOutAndRefParams=0;
            for(int i=0;i<paramTypes.Length;i++)
            {
                paramTypes[i]=paramInfo[i].ParameterType;
                if((!paramInfo[i].IsIn) && paramInfo[i].IsOut)
                    nOutParams++;
                if(paramTypes[i].IsByRef)
                    nOutAndRefParams++;
            }
            int[] refArgs=new int[nOutAndRefParams];

            MethodBuilder delegateMethod=myType.DefineMethod("CallFunction",
                invokeMethod.Attributes,
                returnType,paramTypes);

            // Generates the IL for the method
            ILGenerator generator=delegateMethod.GetILGenerator( );

            generator.DeclareLocal(typeof(object[])); // original arguments
            generator.DeclareLocal(typeof(object[])); // with out-only arguments removed
            generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments
            if(!(returnType == typeof(void)))  // return value
                generator.DeclareLocal(returnType);
            else
                generator.DeclareLocal(typeof(object));
            // Initializes local variables
            generator.Emit(OpCodes.Ldc_I4,paramTypes.Length);
            generator.Emit(OpCodes.Newarr,typeof(object));
            generator.Emit(OpCodes.Stloc_0);
            generator.Emit(OpCodes.Ldc_I4,paramTypes.Length-nOutParams);
            generator.Emit(OpCodes.Newarr,typeof(object));
            generator.Emit(OpCodes.Stloc_1);
            generator.Emit(OpCodes.Ldc_I4,nOutAndRefParams);
            generator.Emit(OpCodes.Newarr,typeof(int));
            generator.Emit(OpCodes.Stloc_2);
            // Stores the arguments in the local variables
            for(int iArgs=0,iInArgs=0,iOutArgs=0;iArgs<paramTypes.Length;iArgs++)
            {
                generator.Emit(OpCodes.Ldloc_0);
                generator.Emit(OpCodes.Ldc_I4,iArgs);
                generator.Emit(OpCodes.Ldarg,iArgs+1);
                if(paramTypes[iArgs].IsByRef)
                {
                    if(paramTypes[iArgs].GetElementType().IsValueType)
                    {
                        generator.Emit(OpCodes.Ldobj,paramTypes[iArgs].GetElementType());
                        generator.Emit(OpCodes.Box,paramTypes[iArgs].GetElementType());
                    } else generator.Emit(OpCodes.Ldind_Ref);
                }
                else
                {
                    if(paramTypes[iArgs].IsValueType)
                        generator.Emit(OpCodes.Box,paramTypes[iArgs]);
                }
                generator.Emit(OpCodes.Stelem_Ref);
                if(paramTypes[iArgs].IsByRef)
                {
                    generator.Emit(OpCodes.Ldloc_2);
                    generator.Emit(OpCodes.Ldc_I4,iOutArgs);
                    generator.Emit(OpCodes.Ldc_I4,iArgs);
                    generator.Emit(OpCodes.Stelem_I4);
                    refArgs[iOutArgs]=iArgs;
                    iOutArgs++;
                }
                if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut))
                {
                    generator.Emit(OpCodes.Ldloc_1);
                    generator.Emit(OpCodes.Ldc_I4,iInArgs);
                    generator.Emit(OpCodes.Ldarg,iArgs+1);
                    if(paramTypes[iArgs].IsByRef)
                    {
                        if(paramTypes[iArgs].GetElementType().IsValueType)
                        {
                            generator.Emit(OpCodes.Ldobj,paramTypes[iArgs].GetElementType());
                            generator.Emit(OpCodes.Box,paramTypes[iArgs].GetElementType());
                        }
                        else generator.Emit(OpCodes.Ldind_Ref);
                    }
                    else
                    {
                        if(paramTypes[iArgs].IsValueType)
                            generator.Emit(OpCodes.Box,paramTypes[iArgs]);
                    }
                    generator.Emit(OpCodes.Stelem_Ref);
                    iInArgs++;
                }
            }
            // Calls the callFunction method of the base class
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldloc_0);
            generator.Emit(OpCodes.Ldloc_1);
            generator.Emit(OpCodes.Ldloc_2);
            MethodInfo miGenericEventHandler;
            miGenericEventHandler=delegateParent.GetMethod("callFunction");
            generator.Emit(OpCodes.Call,miGenericEventHandler);
            // Stores return value
            if(returnType == typeof(void))
            {
                generator.Emit(OpCodes.Pop);
                generator.Emit(OpCodes.Ldnull);
            }
            else if(returnType.IsValueType)
            {
                generator.Emit(OpCodes.Unbox,returnType);
                generator.Emit(OpCodes.Ldobj,returnType);
            } else generator.Emit(OpCodes.Castclass,returnType);
            generator.Emit(OpCodes.Stloc_3);
            // Stores new value of out and ref params
            for(int i=0;i<refArgs.Length;i++)
            {
                generator.Emit(OpCodes.Ldarg,refArgs[i]+1);
                generator.Emit(OpCodes.Ldloc_0);
                generator.Emit(OpCodes.Ldc_I4,refArgs[i]);
                generator.Emit(OpCodes.Ldelem_Ref);
                if(paramTypes[refArgs[i]].GetElementType().IsValueType)
                {
                    generator.Emit(OpCodes.Unbox,paramTypes[refArgs[i]].GetElementType());
                    generator.Emit(OpCodes.Ldobj,paramTypes[refArgs[i]].GetElementType());
                    generator.Emit(OpCodes.Stobj,paramTypes[refArgs[i]].GetElementType());
                }
                else
                {
                    generator.Emit(OpCodes.Castclass,paramTypes[refArgs[i]].GetElementType());
                    generator.Emit(OpCodes.Stind_Ref);
                }
            }
            // Returns
            if(!(returnType == typeof(void)))
                generator.Emit(OpCodes.Ldloc_3);
            generator.Emit(OpCodes.Ret);

            // creates the new type
            return myType.CreateType();
        }