7.5 CLR/Lua

The Limax provides a clrlua project, which combines C# with the Lua, supports the interoperability between the C# and Lua, to implement the LuaScriptHandle in the frame of the C# script mode. This chapter describes the functions provided by the clrlua.


  • 7.5.1 Programming interface

    • limax.script.Lua

      When creating this object, a lua virtual machine is created. Using this object could interact with the lua virtual machine.

      Constructor:

      • Lua(limax.script.Lua.ErrorHandle eh)

        The ErrorHandle is defined as the delegation delegate void ErrorHandle(string msg); which is used to accept the lua error message.

      Method:

      • object eval(string code)

        Execute the code chunk represented by the code and return the result.

      • object eval(string codepattern, params object[] parameters)

        Use the variable-length argument lists to fill with the codepattern <0>,<1>......<n> of the codepattern, then execute the chunk, and return the result. The codepatterns are associated through the corresponding created context variables, and should be used as the variable names in the template code, rather than using quotation to mark, or the replacement result will be a name string of context variable.

        The returned result could be any type. Especially, the LuaObject, LuaTable and LuaFunction three types could be returned.

      • Lua name(string chunkname)

        Name the following eval. If the run-time error occurs in the named eval code, this name will be prefixed in the error message for debugging purpose. This name uses UTF8 encoding internally, and non-ASCII characters are not recommended.


    • limax.script.LuaObject

      The Lua object which could not be converted to C# type could be held by the C#. This object does not provide any operation and need to be returned to the lua virtual machine to use in most cases. Those which can not be coverted are described in the type mapping section.


    • limax.script.LuaTable

      This object is derived from the LuaObject, and implements the System.Collections.IDictionary interface and associates to the table of the lua virtual machine. When accessing this object, the corresponding table of the virtual machine is also accessed, and the update operation executed on this object will be reflected to the corresponding table of the virtual machine. vice versa.


      Note, the object created through limax.script.Lua is named as the Lua operating object in the next content to distinguish the LuaObject.


    • limax.script.LuaFunction

      A variable-length argument delegation, encapsulates the object derived from LuaObject and associated with function of the lua virtual machine. Calling on this delegation is equivalent to calling the corresponding function of the virtual machine.


  • 7.5.2 Interoperability example between C# and Lua

    First, define the Lua lua = new Lua((string msg)=>Console.WriteLine(msg));


    • C# operates Lua

      The C# operates the Lua through calling the eval method.

      • hello world


        lua.eval("print('hello world')");
        lua.eval("print(<0>)", "hello world");
        Console.WriteLine(lua.eval("return 'hello world'"));
        Console.WriteLine(lua.eval("return <0>", "hello world"));
        

        Output:

        hello world

        hello world

        hello world

        hello world

        It is no need to describe the first line. The second line describes the usage of the codepattern. The third line describes that the eval could return the value held by the lua virtual machine. The forth line describes that a value could be repeatedly trasferred between the C# and Lua.


      • 好好学习,天天向上


        lua.eval("print('好好学习,天天向上')");
        lua.eval("print(<0>)", "好好学习,天天向上");
        Console.WriteLine(lua.eval("return '好好学习,天天向上'"));
        Console.WriteLine(lua.eval("return <0>", "好好学习,天天向上"));
        

        Output:

        濂藉ソ瀛︿範锛屽ぉ澶╁悜涓

        濂藉ソ瀛︿範锛屽ぉ澶╁悜涓

        好好学习,天天向上

        好好学习,天天向上

        This example explains that the Unicode character string of the C# uses the UTF8 to encode when transffering to the Lua and uses the UTF8 to decode when passing back from the Lua. So the Unicode character is the gibberish in the Lua virtual machine, and is correct in the C#.


      • The executing code returns the multiple values


        object[] a = (object[])lua.eval("return 1,2,3");
        foreach (object o in a)
        	Console.WriteLine(o);
        

        Output:

        1

        2

        3

        This example explains that if the Lua code returns the multiple values, these values are placed in the object[] to return.


      • The executing code returns the table


        IDictionary dict = (IDictionary)lua.eval("t = { a = 'A', b ='B' }\n return t ");
        foreach (DictionaryEntry e in dict)	Console.WriteLine(e.Key + ":" + e.Value);
        

        Output:

        b:B

        a:A

        Continue to execute:


        dict.Remove("a");
        dict.Add("c", "C");
        lua.eval("print (t.a)");
        lua.eval("print (t.c)");
        

        Output:

        nil

        C

        From the above result, the modification of the C# affects the internal table of the lua.

        Continue to execute:


        lua.eval("t.d = 100");
        foreach (DictionaryEntry e in dict)	Console.WriteLine(e.Key + ":" + e.Value);
        

        Output:

        d:100

        c:C

        b:B

        From the above result, the modification to the internal table of the Lua also is reflected to the C#.


      • The executing code returns the function


        LuaFunction func = (LuaFunction)lua.eval("return function(a,b) return a + b; end");
        Console.WriteLine(func (10, 20));
        

        Output:

        30

        From the above result, returning a lua function is very easy to use in the C#.


    • Lua operates C#

      First, define a C# example class.


      public class TestLua
      {
      	public TestLua() { Console.WriteLine("Construct TestLua"); acc = add; }
      	public TestLua(int x) { Console.WriteLine("Construct TestLua with " + x); acc = add; }
      	public int add(int a, int b) { return a + b; }
      	public string mystr;
      	public int Prop { get; set; }
      	public int this[int x]
      	{
      		get { return x + 1; }
      		set { Console.WriteLine("Indexed Property set key = " + x + " value = " + value); }
      	}
      	public delegate int ACC(int a, int b);
      	public ACC acc;
      }
      

      It is noted that the object construction functions, methods, fields, attributes, delegations accessed by the Lua must be declared as public.

      • Construct the object


        lua.eval("t0 = <0>()", typeof(TestLua));
        lua.eval("t1 = <0>(100)", typeof(TestLua));
        Console.WriteLine(lua.eval("return t0") is TestLua);
        

        Output:

        Construct TestLua

        Construct TestLua with 100

        True

        Here the TestLua class is passed into the Lua virtual machine, the methods are directly called on the class and create the object. Through controlling the number of the parameter, the different methods are selected to call. The third line passes the variable t0 created in the Lua back to the C# to verify, and the result is the TestLua object.


      • Call method


        lua.eval("print (t0.add(1,2))");
        

        Output:

        3

        If it is the static method of the class, it also could be called.


      • Access field


        lua.eval("print(t0.mystr)");
        lua.eval("t0.mystr='hello world'");
        Console.WriteLine(lua.eval("return t0.mystr"));
        Console.WriteLine(((TestLua)lua.eval("return t0")).mystr);
        

        Output

        nil

        helloworld

        helloworld

        The first line code outputs the content of the mystr, this field does not be initialized when constructing the object, so the null in the C# corresponding to the nil in the Lua is output. The second line sets the field content of the mystr. So the third line and the forth line correctly return the setted content.


      • Access the normal attribute


        lua.eval("print(t0.Prop)");
        lua.eval("t0.Prop = t0.Prop + 10");
        Console.WriteLine(lua.eval("return t0.Prop"));
        

        Output:

        0

        10

        The first line code outputs the default initialization value 0 of the Prop. The second line is equivalent to read this attribute, then sets this attribute and adds 10 into the attribute. The third line outputs 10.


      • Access the indexed attribute


        lua.eval("print(t0[100])");
        lua.eval("t0[200] = 300");	
        

        Output:

        101

        Indexed Property set key = 200 value = 300

        Here the two methods of the indexed attribute are correctly called.


      • Access the delegation


        lua.eval("print(t0.acc(100,200))");
        

        Output:

        300

        Compare with the previous C# code, the acc here actually is a delegation and points to the add method. So actually the add is executed.


      • Refer to the charpter <The specification that the script language accesses C#> for the details about the Lua accessing C#


    • Complex interaction

      First define the delegation FN


      public delegate long FN(object f, long a);
      

      Then execute the below code


      FN fn = (object f, long a) => 
      (long)lua.eval("if<1><2 then return<1>else return<0>(<0>,<1<-1)+<0>(<0>,<1>-2)end", f, a);
      lua.eval("print(<0>(<0>,<1>))", fn, 9);
      

      Output:

      34

      Actually, this program is indirectly recursive between the C# and Lua to calculate the ninth item of the Fibonacci sequence. This illustrates the possibility of the complex interaction between the C# and Lua.


Prev Next