http://blog.csdn.net/rcfalcon/article/details/5583095
今天翻了一下google,翻出GameDev.net上一篇老外的文章,叫《Using Lua with C#》,看了一下,它的方法不错。(改天考虑翻译这篇文章),不过他的示例代码实在是太太太冗长了,大部分是生成函数介绍和函数帮助文档等,直接忽略。把它最核心的东西拿过来,然后自己封装了一下,用起来感觉不错。
基本思想是,使用C#的Attribute来标记函数,实现自动绑定。
核心部分代码如下(LuaFramework.cs):
我的LUA API类如下,用于实现C# for lua的函数(LuaAPI.cs)
最后看调用代码,是不是很简单
LUA代码如下
lua1();
lua2();
lua3("test");
原文:
http://www.gamedev.net/page/resources/_/technical/game-programming/using-lua-with-c-r2275
using System; using LuaInterface; namespace LuaCon { class Program { private bool bRunning = true; public static Lua pLuaVM = null; public Program() { pLuaVM = new Lua(); } static void Main(string[] args) { Program pPrg = new Program(); pPrg.Run(); } public void Run() { String strInput; while (bRunning) { Console.Write("> "); strInput = Console.ReadLine(); if (strInput == "quit") bRunning = false; else { Console.WriteLine(); try { pLuaVM.DoString(strInput); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { Console.WriteLine(); } } } } } }Compile it and run it, you have your very own Lua console to fool around with. Not very useful as it is, but it's a start. The next thing we'd want to do is to expose some of our own functions tothe Lua virtual machine. Again, LuaInterface comes to the rescue: Lua.RegisterFunction(Name, Target, Method)will do just that. The parameters needed are a string, an objectinstance and a MethodInfo instance for the method we want.
public void quit() { bRunning = false; }Amazingly simple, as you see. It just switches the running flag off. To make it available for Lua, we have to modify the main() function a bit:
static void Main(String[] args) { Program pPrg = new Program(); Type pPrgType = pPrg.GetType(); MethodInfo mInfo = pPrgType.GetMethod("quit"); pPrg.pLuaVM.RegisterFunction("quit", pPrg, mInfo); pPrg.Run(); }Now, take out the ugly hack, the Run method looks like this:
public void Run() { String strInput; while (bRunning) { Console.Write("> "); strInput = Console.ReadLine(); Console.WriteLine(); try { pLuaVM.DoString(strInput); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { Console.WriteLine(); } } }Add System.Reflection to the list of usages and recompile. Run and now whenever you call quit() from the console, it will actually be Lua makingit happen. Of course, adding functions like this is a bit awkward if you end up having hundreds of them. It also requires you to touch several parts of the program if you want to add a new function,which often leads to forgetting about some part of the process. Wouldn't it be nice if we could just flag a function somehow in it's declaration and have it automagically picked up by the Lua VM?That way, we would just have to worry about writing them. To fix this, we'll have a look at one of my favourite features of C#: Attributes.
public class AttrLuaFunc : Attribute { private String FunctionName; private String FunctionDoc; private String[] FunctionParameters = null; public AttrLuaFunc(String strFuncName, String strFuncDoc, params String[] strParamDocs) { FunctionName = strFuncName; FunctionDoc = strFuncDoc; FunctionParameters = strParamDocs; } public AttrLuaFunc(String strFuncName, String strFuncDoc) { FunctionName = strFuncName; FunctionDoc = strFuncDoc; } public String getFuncName() { return FunctionName; } public String getFuncDoc() { return FunctionDoc; } public String[] getFuncParams() { return FunctionParameters; } }It has a function name, a function "doc" string and an array of parameter definitions. With it, the declaration of our "quit" function would look like this:
[AttrLuaFunc("quit", "Exit the program.")] public void quit() { bRunning = false; }Next, we want another class to hold the structure of functions exposed to Lua, just to keep track of everything and have some fancy help built in:
public class LuaFuncDescriptor { private String FunctionName; private String FunctionDoc; private ArrayList FunctionParameters; private ArrayList FunctionParamDocs; private String FunctionDocString; public LuaFuncDescriptor(String strFuncName, String strFuncDoc, ArrayList strParams, ArrayList strParamDocs) { FunctionName = strFuncName; FunctionDoc = strFuncDoc; FunctionParameters = strParams; FunctionParamDocs = strParamDocs; String strFuncHeader = strFuncName + "(%params%) - " + strFuncDoc; String strFuncBody = "\n\n"; String strFuncParams = ""; Boolean bFirst = true; for (int i = 0; i < strParams.Count; i++) { if (!bFirst) strFuncParams += ", "; strFuncParams += strParams[i]; strFuncBody += "\t" + strParams[i] + "\t\t" + strParamDocs[i] + "\n"; bFirst = false; } strFuncBody = strFuncBody.Substring(0, strFuncBody.Length - 1); if (bFirst) strFuncBody = strFuncBody.Substring(0, strFuncBody.Length - 1); FunctionDocString = strFuncHeader.Replace("%params%", strFuncParams) + strFuncBody; } public String getFuncName() { return FunctionName; } public String getFuncDoc() { return FunctionDoc; } public ArrayList getFuncParams() { return FunctionParameters; } public ArrayList getFuncParamDocs() { return FunctionParamDocs; } public String getFuncHeader() { if (FunctionDocString.IndexOf("\n") == -1) return FunctionDocString; return FunctionDocString.Substring(0, FunctionDocString.IndexOf("\n")); } public String getFuncFullDoc() { return FunctionDocString; } }We want the function to be called "quit" in Lua, and its helpful doc string just tells the user what it does. We also have a function descriptor to keep track of all added functions. So far sogood, now how we do make Lua aware of those attributes to pick everything up? LuaInterface has nothing like that (yet), but we can make it fairly easily with a function. Let's call it "registerLuaFunctions":
public static void registerLuaFunctions(Object pTarget) { // Sanity checks if (pLuaVM == null || pLuaFuncs == null) return; // Get the target type Type pTrgType = pTarget.GetType(); // ... and simply iterate through all it's methods foreach (MethodInfo mInfo in pTrgType.GetMethods()) { // ... then through all this method's attributes foreach (Attribute attr in Attribute.GetCustomAttributes(mInfo)) { // and if they happen to be one of our AttrLuaFunc attributes if (attr.GetType() == typeof(AttrLuaFunc)) { AttrLuaFunc pAttr = (AttrLuaFunc) attr; Hashtable pParams = new Hashtable(); // Get the desired function name and doc string, along with parameter info String strFName = pAttr.getFuncName(); String strFDoc = pAttr.getFuncDoc(); String[] pPrmDocs = pAttr.getFuncParams(); // Now get the expected parameters from the MethodInfo object ParameterInfo[] pPrmInfo = mInfo.GetParameters(); // If they don't match, someone forgot to add some documentation to the // attribute, complain and go to the next method if (pPrmDocs != null && (pPrmInfo.Length != pPrmDocs.Length)) { Console.WriteLine("Function " + mInfo.Name + " (exported as " + strFName + ") argument number mismatch. Declared " + pPrmDocs.Length + " but requires " + pPrmInfo.Length + "."); break; } // Build a parameter <-> parameter doc hashtable for (int i = 0; i < pPrmInfo.Length; i++) { pParams.Add(pPrmInfo[i].Name, pPrmDocs[i]); } // Get a new function descriptor from this information LuaFuncDescriptor pDesc = new LuaFuncDescriptor(strFName, strFDoc, pParams); // Add it to the global hashtable pLuaFuncs.Add(strFName, pDesc); // And tell the VM to register it. pLuaVM.RegisterFunction(strFName, pTarget, mInfo); } } } }Now we modify the Program class and constructor to look like this:
public static Hashtable pLuaFuncs = null; public Program() { pLuaVM = new Lua(); pLuaFuncs = new Hashtable(); registerLuaFunctions(this); }That's it. Now, as soon as you instantiate the Program class, it will register all it's functions automatically. Since the LuaVM, function hashtable and registerLuaFuncs method are all static, youcan call them from wherever and add new functions to it, keeping a single centralized VM and function list.
[AttrLuaFunc("help", "List available commands.")] public void help() { Console.WriteLine("Available commands: "); Console.WriteLine(); IDictionaryEnumerator Funcs = pLuaFuncs.GetEnumerator(); while (Funcs.MoveNext()) { Console.WriteLine(((LuaFuncDescriptor)Funcs.Value).getFuncHeader()); } } [AttrLuaFunc("helpcmd", "Show help for a given command", "Command to get help of.")] public void help(String strCmd) { if (!pLuaFuncs.ContainsKey(strCmd)) { Console.WriteLine("No such function or package: " + strCmd); return; } LuaFuncDescriptor pDesc = (LuaFuncDescriptor)pLuaFuncs[strCmd]; Console.WriteLine(pDesc.getFuncFullDoc()); }It's as simple as that, just write those two functions and they get inserted without you having to move a finger. They are straightforward. The first one lists all available commands (exposed from your application) and the second one gives detailed help on any command. Compile, build and try:
help() helpcmd("help") helpcmd("helpcmd")Impressive, huh?