/* * This file is part of LuaInterface. * * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. * Copyright (C) 2012 Megax * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ using System; using System.Threading; using System.Reflection; #if !MONOTOUCH using System.Reflection.Emit; #endif using System.Collections; using System.Collections.Generic; using LuaInterface.Method; namespace LuaInterface { /* * Dynamically generates new types from existing types and * Lua function and table values. Generated types are event handlers, * delegates, interface implementations and subclasses. * * Author: Fabio Mascarenhas * Version: 1.0 */ class CodeGeneration { private Dictionary classCollection = new Dictionary (); private Dictionary eventHandlerCollection = new Dictionary (); private Dictionary delegateCollection = new Dictionary (); private static readonly CodeGeneration instance = new CodeGeneration (); private Type eventHandlerParent = typeof(LuaEventHandler); private Type delegateParent = typeof(LuaDelegate); private Type classHelper = typeof(LuaClassHelper); private AssemblyName assemblyName; #if !MONOTOUCH private AssemblyBuilder newAssembly; private ModuleBuilder newModule; #endif private int luaClassNumber = 1; static CodeGeneration () { } private CodeGeneration () { // Create an assembly name assemblyName = new AssemblyName (); assemblyName.Name = "LuaInterface_generatedcode"; // Create a new assembly with one module. #if !MONOTOUCH newAssembly = Thread.GetDomain ().DefineDynamicAssembly (assemblyName, AssemblyBuilderAccess.Run); newModule = newAssembly.DefineDynamicModule ("LuaInterface_generatedcode"); #endif } /* * Singleton instance of the class */ public static CodeGeneration Instance { get { return instance; } } /* * Generates an event handler that calls a Lua function */ private Type GenerateEvent (Type eventHandlerType) { #if MONOTOUCH throw new NotImplementedException (" Emit not available on MonoTouch "); #else string typeName; lock (this) { typeName = "LuaGeneratedClass" + luaClassNumber; luaClassNumber++; } // Define a public class in the assembly, called typeName var myType = newModule.DefineType (typeName, TypeAttributes.Public, eventHandlerParent); // Defines the handler method. Its signature is void(object, ) var paramTypes = new Type[2]; paramTypes [0] = typeof(object); paramTypes [1] = eventHandlerType; var returnType = typeof(void); var handleMethod = myType.DefineMethod ("HandleEvent", MethodAttributes.Public | MethodAttributes.HideBySig, returnType, paramTypes); // Emits the IL for the method. It loads the arguments // and calls the handleEvent method of the base class ILGenerator generator = handleMethod.GetILGenerator (); generator.Emit (OpCodes.Ldarg_0); generator.Emit (OpCodes.Ldarg_1); generator.Emit (OpCodes.Ldarg_2); var miGenericEventHandler = eventHandlerParent.GetMethod ("handleEvent"); generator.Emit (OpCodes.Call, miGenericEventHandler); // returns generator.Emit (OpCodes.Ret); // creates the new type return myType.CreateType (); #endif } /* * Generates a type that can be used for instantiating a delegate * of the provided type, given a Lua function. */ private Type GenerateDelegate (Type delegateType) { #if MONOTOUCH throw new NotImplementedException ("GenerateDelegate is not available on iOS, please register your LuaDelegate type with Lua.RegisterLuaDelegateType( yourDelegate, theLuaDelegateHandler) "); #else string typeName; lock (this) { typeName = "LuaGeneratedClass" + luaClassNumber; luaClassNumber++; } // Define a public class in the assembly, called typeName var myType = newModule.DefineType (typeName, TypeAttributes.Public, delegateParent); // Defines the delegate method with the same signature as the // Invoke method of delegateType var invokeMethod = delegateType.GetMethod ("Invoke"); var paramInfo = invokeMethod.GetParameters (); var paramTypes = new Type[paramInfo.Length]; var 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]; var 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); var 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); return myType.CreateType (); // creates the new type #endif } void GetReturnTypesFromClass (Type klass, out Type[][] returnTypes) { var classMethods = klass.GetMethods (); returnTypes = new Type[classMethods.Length][]; int i = 0; foreach (var method in classMethods) { if (klass.IsInterface) { GetReturnTypesFromMethod (method, out returnTypes [i]); i++; } else { if (!method.IsPrivate && !method.IsFinal && method.IsVirtual) { GetReturnTypesFromMethod (method, out returnTypes [i]); i++; } } } } /* * Generates an implementation of klass, if it is an interface, or * a subclass of klass that delegates its virtual methods to a Lua table. */ public void GenerateClass (Type klass, out Type newType, out Type[][] returnTypes) { #if MONOTOUCH throw new NotImplementedException (" Emit not available on MonoTouch "); #else string typeName; lock (this) { typeName = "LuaGeneratedClass" + luaClassNumber; luaClassNumber++; } TypeBuilder myType; // Define a public class in the assembly, called typeName if (klass.IsInterface) myType = newModule.DefineType (typeName, TypeAttributes.Public, typeof(object), new Type[] { klass, typeof(ILuaGeneratedType) }); else myType = newModule.DefineType (typeName, TypeAttributes.Public, klass, new Type[] { typeof(ILuaGeneratedType) }); // Field that stores the Lua table var luaTableField = myType.DefineField ("__luaInterface_luaTable", typeof(LuaTable), FieldAttributes.Public); // Field that stores the return types array var returnTypesField = myType.DefineField ("__luaInterface_returnTypes", typeof(Type[][]), FieldAttributes.Public); // Generates the constructor for the new type, it takes a Lua table and an array // of return types and stores them in the respective fields var constructor = myType.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(LuaTable), typeof(Type[][]) }); ILGenerator generator = constructor.GetILGenerator (); generator.Emit (OpCodes.Ldarg_0); if (klass.IsInterface) generator.Emit (OpCodes.Call, typeof(object).GetConstructor (Type.EmptyTypes)); else generator.Emit (OpCodes.Call, klass.GetConstructor (Type.EmptyTypes)); generator.Emit (OpCodes.Ldarg_0); generator.Emit (OpCodes.Ldarg_1); generator.Emit (OpCodes.Stfld, luaTableField); generator.Emit (OpCodes.Ldarg_0); generator.Emit (OpCodes.Ldarg_2); generator.Emit (OpCodes.Stfld, returnTypesField); generator.Emit (OpCodes.Ret); // Generates overriden versions of the klass' public virtual methods var classMethods = klass.GetMethods (); returnTypes = new Type[classMethods.Length][]; int i = 0; foreach (var method in classMethods) { if (klass.IsInterface) { GenerateMethod (myType, method, MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot, i, luaTableField, returnTypesField, false, out returnTypes [i]); i++; } else { if (!method.IsPrivate && !method.IsFinal && method.IsVirtual) { GenerateMethod (myType, method, (method.Attributes | MethodAttributes.NewSlot) ^ MethodAttributes.NewSlot, i, luaTableField, returnTypesField, true, out returnTypes [i]); i++; } } } // Generates an implementation of the __luaInterface_getLuaTable method var returnTableMethod = myType.DefineMethod ("__luaInterface_getLuaTable", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(LuaTable), new Type[0]); myType.DefineMethodOverride (returnTableMethod, typeof(ILuaGeneratedType).GetMethod ("__luaInterface_getLuaTable")); generator = returnTableMethod.GetILGenerator (); generator.Emit (OpCodes.Ldfld, luaTableField); generator.Emit (OpCodes.Ret); newType = myType.CreateType (); // Creates the type #endif } void GetReturnTypesFromMethod (MethodInfo method, out Type[] returnTypes) { var paramInfo = method.GetParameters (); var paramTypes = new Type[paramInfo.Length]; var returnTypesList = new List (); // Counts out and ref parameters, for later use, // and creates the list of return types int nOutParams = 0; int nOutAndRefParams = 0; var returnType = method.ReturnType; returnTypesList.Add (returnType); 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) { returnTypesList.Add (paramTypes [i].GetElementType ()); nOutAndRefParams++; } } int[] refArgs = new int[nOutAndRefParams]; returnTypes = returnTypesList.ToArray (); } #if !MONOTOUCH /* * Generates an overriden implementation of method inside myType that delegates * to a function in a Lua table with the same name, if the function exists. If it * doesn't the method calls the base method (or does nothing, in case of interface * implementations). */ private void GenerateMethod (TypeBuilder myType, MethodInfo method, MethodAttributes attributes, int methodIndex, FieldInfo luaTableField, FieldInfo returnTypesField, bool generateBase, out Type[] returnTypes) { var paramInfo = method.GetParameters (); var paramTypes = new Type[paramInfo.Length]; var returnTypesList = new List (); // Counts out and ref parameters, for later use, // and creates the list of return types int nOutParams = 0; int nOutAndRefParams = 0; var returnType = method.ReturnType; returnTypesList.Add (returnType); 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) { returnTypesList.Add (paramTypes [i].GetElementType ()); nOutAndRefParams++; } } int[] refArgs = new int[nOutAndRefParams]; returnTypes = returnTypesList.ToArray (); // Generates a version of the method that calls the base implementation // directly, for use by the base field of the table if (generateBase) { var baseMethod = myType.DefineMethod ("__luaInterface_base_" + method.Name, MethodAttributes.Private | MethodAttributes.NewSlot | MethodAttributes.HideBySig, returnType, paramTypes); ILGenerator generatorBase = baseMethod.GetILGenerator (); generatorBase.Emit (OpCodes.Ldarg_0); for (int i = 0; i < paramTypes.Length; i++) generatorBase.Emit (OpCodes.Ldarg, i + 1); generatorBase.Emit (OpCodes.Call, method); if (returnType == typeof(void)) generatorBase.Emit (OpCodes.Pop); generatorBase.Emit (OpCodes.Ret); } // Defines the method var methodImpl = myType.DefineMethod (method.Name, attributes, returnType, paramTypes); // If it's an implementation of an interface tells what method it // is overriding if (myType.BaseType.Equals (typeof(object))) myType.DefineMethodOverride (methodImpl, method); ILGenerator generator = methodImpl.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 + 1); 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); generator.Emit (OpCodes.Ldloc_1); generator.Emit (OpCodes.Ldc_I4_0); generator.Emit (OpCodes.Ldarg_0); generator.Emit (OpCodes.Ldfld, luaTableField); generator.Emit (OpCodes.Stelem_Ref); // Stores the arguments into the local variables, as needed for (int iArgs = 0, iInArgs = 1, 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++; } } // Gets the function the method will delegate to by calling // the getTableFunction method of class LuaClassHelper generator.Emit (OpCodes.Ldarg_0); generator.Emit (OpCodes.Ldfld, luaTableField); generator.Emit (OpCodes.Ldstr, method.Name); generator.Emit (OpCodes.Call, classHelper.GetMethod ("getTableFunction")); var lab1 = generator.DefineLabel (); generator.Emit (OpCodes.Dup); generator.Emit (OpCodes.Brtrue_S, lab1); // Function does not exist, call base method generator.Emit (OpCodes.Pop); if (!method.IsAbstract) { generator.Emit (OpCodes.Ldarg_0); for (int i = 0; i < paramTypes.Length; i++) generator.Emit (OpCodes.Ldarg, i + 1); generator.Emit (OpCodes.Call, method); if (returnType == typeof(void)) generator.Emit (OpCodes.Pop); generator.Emit (OpCodes.Ret); generator.Emit (OpCodes.Ldnull); } else generator.Emit (OpCodes.Ldnull); var lab2 = generator.DefineLabel (); generator.Emit (OpCodes.Br_S, lab2); generator.MarkLabel (lab1); // Function exists, call using method callFunction of LuaClassHelper generator.Emit (OpCodes.Ldloc_0); generator.Emit (OpCodes.Ldarg_0); generator.Emit (OpCodes.Ldfld, returnTypesField); generator.Emit (OpCodes.Ldc_I4, methodIndex); generator.Emit (OpCodes.Ldelem_Ref); generator.Emit (OpCodes.Ldloc_1); generator.Emit (OpCodes.Ldloc_2); generator.Emit (OpCodes.Call, classHelper.GetMethod ("callFunction")); generator.MarkLabel (lab2); // Stores the function 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); // Sets return values of out and ref parameters 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); } #endif /* * Gets an event handler for the event type that delegates to the eventHandler Lua function. * Caches the generated type. */ public LuaEventHandler GetEvent (Type eventHandlerType, LuaFunction eventHandler) { #if MONOTOUCH throw new NotImplementedException (" Emit not available on MonoTouch "); #else Type eventConsumerType; if (eventHandlerCollection.ContainsKey (eventHandlerType)) eventConsumerType = eventHandlerCollection [eventHandlerType]; else { eventConsumerType = GenerateEvent (eventHandlerType); eventHandlerCollection [eventHandlerType] = eventConsumerType; } var luaEventHandler = (LuaEventHandler)Activator.CreateInstance (eventConsumerType); luaEventHandler.handler = eventHandler; return luaEventHandler; #endif } public void RegisterLuaDelegateType (Type delegateType, Type luaDelegateType) { delegateCollection [delegateType] = luaDelegateType; } public void RegisterLuaClassType (Type klass, Type luaClass) { LuaClassType luaClassType = new LuaClassType (); luaClassType.klass = luaClass; GetReturnTypesFromClass (klass, out luaClassType.returnTypes); classCollection [klass] = luaClassType; } /* * Gets a delegate with delegateType that calls the luaFunc Lua function * Caches the generated type. */ public Delegate GetDelegate (Type delegateType, LuaFunction luaFunc) { var returnTypes = new List (); Type luaDelegateType; if (delegateCollection.ContainsKey (delegateType)) luaDelegateType = delegateCollection [delegateType]; else { luaDelegateType = GenerateDelegate (delegateType); delegateCollection [delegateType] = luaDelegateType; } var methodInfo = delegateType.GetMethod ("Invoke"); returnTypes.Add (methodInfo.ReturnType); foreach (ParameterInfo paramInfo in methodInfo.GetParameters()) { if (paramInfo.ParameterType.IsByRef) returnTypes.Add (paramInfo.ParameterType); } var luaDelegate = (LuaDelegate)Activator.CreateInstance (luaDelegateType); luaDelegate.function = luaFunc; luaDelegate.returnTypes = returnTypes.ToArray (); return Delegate.CreateDelegate (delegateType, luaDelegate, "CallFunction"); } /* * Gets an instance of an implementation of the klass interface or * subclass of klass that delegates public virtual methods to the * luaTable table. * Caches the generated type. */ public object GetClassInstance (Type klass, LuaTable luaTable) { LuaClassType luaClassType; if (classCollection.ContainsKey (klass)) luaClassType = classCollection [klass]; else { luaClassType = new LuaClassType (); GenerateClass (klass, out luaClassType.klass, out luaClassType.returnTypes); classCollection [klass] = luaClassType; } return Activator.CreateInstance (luaClassType.klass, new object[] { luaTable, luaClassType.returnTypes }); } } }