XLua学习笔记

实现原理:

热补丁的基本原理其实非常简单,了解后任何程序员都很容易分析出开销,比如对于这个类

public class Calc
{
    int Add(int a, int b)
    {
        return a + b
    }
}

打了hotfix标签后,xLua会在il层面注入代码,注入之后这个类会类似这样:

public class Calc
{
    static Func<object, int, int, int> hotfix_Add = null;
    int Add(int a, int b)
    {
        if (hotfix_Add != null) return hotfix_Add(this, a, b);
        return a + b
    }
}

如果lua中执行了hotfix调用,hotfix_Add会指向一个lua的适配函数。

性能开销:

如果不打补丁,就一个if判断,比注入前多执行两条很轻量级的指令(Ldsfld,Brfalse),在window下测试,这两指令加起来仅相当于空函数调用开销的十分之一到五分之一。

内存开销:

每个函数会多一个静态delegate引用,注意是静态的,和对象实例个数无关

使用建议

  1. 对所有较大可能变动的类型加上Hotfix标识;
  2. 建议用反射找出所有函数参数、字段、属性、事件涉及的delegate类型,标注CSharpCallLua;
  3. 业务代码、引擎API、系统API,需要在Lua补丁里头高性能访问的类型,加上LuaCallCSharp;
  4. 引擎API、系统API可能被代码剪裁调(C#无引用的地方都会被剪裁),如果觉得可能会新增C#代码之外的API调用,这些API所在的类型要么加LuaCallCSharp,要么加ReflectionUse;

一、加载方式

LuaEnv m_LuaEnv = new LuaEnv();

m_LuaEnv.DoString("require 'CSharpCallLua'");

二、C#访问Lua

1.获取一个全局基本数据类型

int test1 = m_LuaEnv.Global.Get<int>("test1");

print(test1);

string test2 = m_LuaEnv.Global.Get<string>("test2");

print(test2);

bool test3 = m_LuaEnv.Global.Get<bool>("test3");

print(test3);

2.访问一个全局的table

//1.映射到class的过程是值拷贝,如果class比较复杂代价会比较大。而且修改class的字段值不会同步到table,反过来也不会。
Person p = m_LuaEnv.Global.Get<Person>("person");
print(p.name + " " + p.age);

//2.映射到interface,推荐
IPerson p = m_LuaEnv.Global.Get<IPerson>("person");
print(p.name + " " + p.age);
p.name = "Lily";
m_LuaEnv.DoString("print(person.name)");
//p.eat(p, 2, 3);会把自身对象自动传入,在lua代码中,函数第一个参数为自身对象
p.eat(2, 3);
p.walk(11, 11);
p.work(22, 22);

//3.1 映射到Dictionary
Dictionary<object, object> dic = m_LuaEnv.Global.Get<Dictionary<object, object>>("person");
foreach (var item in dic)
{
    print(item.Key + " " + item.Value);
}

//3.2 映射到list
List<object> list = m_LuaEnv.Global.Get<List<object>>("person");
foreach (var item in list)
{
    print(item);
}

//4.映射到LuaTable,运行速度太慢,不推荐
//LuaTable tab = m_LuaEnv.Global.Get<LuaTable>("person");
//print(tab.Get<string>("name"));

public class Person
{
    public string name;
    public int age;
}

[CSharpCallLua]
interface IPerson
{
    string name { get; set; }
    int age { get; set; }
    void eat(int para1, int para2);
    void walk(int para1, int para2);
    void work(int para1, int para2);
}

3.映射一个全局的函数

//lua的多返回值,从左到右对应C#的返回值,out参数,ref参数
//注意:当ref参数在out参数之前,lua的多返回值,会先给ref参数赋值,再给out参数赋值,会影响ref值
//最好的做法是把ref参数放到out参数之后,保证多返回值跟out参数对应,ref参数也会取到正确的值
//private delegate int Add(int a, int b, ref int para1, out int res1, out int res2);

[CSharpCallLua]
private delegate int Add(int a, int b, out int res1, out int res2, ref int para1);

//1.把lua的函数映射到delegate, 推荐       

int para1 = 1;
int res1;
int res2;

Add add = m_LuaEnv.Global.Get<Add>("Add");
int res = add(20, 20, out res1, out res2, ref para1);
print("para1 : " + para1);
print("res : " + res + " res1 : " + res1 + " res2 : " + res2);

1.1 映射到一个没有传入参数的Action(也可以使用delgate)

Action action = luaenv.Global.Get<Action>("e");
action();

1.2 delegate可以返回更复杂的类型,甚至是另外一个delegate

C#:

[CSharpCallLua]
public delegate Action GetE();

Action action = luaenv.Global.Get<Action>("e");
action();

GetE ret_e = luaenv.Global.Get<GetE>("ret_e");//delegate可以返回更复杂的类型,甚至是另外一个delegate

action = ret_e();
action();

lua:

function e()
    print('i am e')
end

function ret_e()
     print('ret_e called')
         return e
end

//2.映射到luaFunction,性能太差,不推荐       

LuaFunction func = m_LuaEnv.Global.Get<LuaFunction>("Add");
object[] objs = func.Call(10, 20);
foreach (var item in objs)
{
    print(item);
}

三、Lua调用C#

1.new C#对象

对应到Lua是这样:

local newGameObj = CS.UnityEngine.GameObject()

基本类似,除了:

1、lua里头没有new关键字;

2、所有C#相关的都放到CS下,包括构造函数,静态成员属性、方法;

如果有多个构造函数呢?放心,xlua支持重载,比如你要调用GameObject的带一个string参数的构造函数,这么写:

local newGameObj2 = CS.UnityEngine.GameObject('helloworld')

2.访问C#静态属性,方法

读静态属性

CS.UnityEngine.Time.deltaTime

写静态属性

CS.UnityEngine.Time.timeScale = 0.5

调用静态方法

CS.UnityEngine.GameObject.Find('helloworld')

小技巧:如果需要经常访问的类,可以先用局部变量引用后访问,除了减少敲代码的时间,还能提高性能:

local GameObject = CS.UnityEngine.GameObject

GameObject.Find('helloworld')

3.访问C#成员属性,方法

读成员属性

testobj.DMF

写成员属性

testobj.DMF = 1024

调用成员方法

注意:调用成员方法,第一个参数需要传该对象,建议用冒号语法糖,如下

testobj:DMFunc()

4.xlua.private_accessible访问私有方法

在最新的版本中,不使用xlua.private_accessible私有的变量也可以访问,但是私有方法还是要使用xlua.private_accessible,才能访问。

lua:

local PrivateOverrideClass = CS.Tutorial.PrivateOverrideClass
local priObj=PrivateOverrideClass()
priObj:TestFunc(100.0)
priObj:TestFunc('hello')
xlua.private_accessible(PrivateOverrideClass);
priObj:TestFunc(100.0)
priObj:TestFunc('hello')

C#:

[LuaCallCSharp]
public class PrivateOverrideClass
{
    public void TestFunc(int i)
    {
        Debug.Log("TestFunc(int i), i = " + i);
    }

    public void TestFunc(string i)
    {
        Debug.Log("TestFunc(string i), i = " + i);
    }

    private void TestFunc(double i)
    {
        Debug.Log("TestFunc(double i), i = " + i);
    }
}

5.父类属性,方法

xlua支持(通过派生类)访问基类的静态属性,静态方法,(通过派生类实例)访问基类的成员属性,成员方法    

--访问成员属性,方法
local DerivedClass = CS.Tutorial.DerivedClass
local testobj = DerivedClass()
testobj.DMF = 1024--设置成员属性
print(testobj.DMF)--读取成员属性
testobj:DMFunc()--成员方法

 

--基类属性,方法
print(DerivedClass.BSF)--读基类静态属性
DerivedClass.BSF = 2048--写基类静态属性
DerivedClass.BSFunc();--基类静态方法
print(testobj.BMF)--读基类成员属性
testobj.BMF = 4096--写基类成员属性
testobj:BMFunc()--基类方法调用

6.可变参数方法

对于C#的如下方法:

void VariableParamsFunc(int a, params string[] strs)

可以在lua里头这样调用:

testobj:VariableParamsFunc(5, 'hello', 'john')

7.枚举类型

lua:

--调用枚举

print(CS.EnemyType.Normal)

--枚举类将支持__CastFrom方法,可以实现从一个整数或者字符串到枚举值的转换

print(CS.EnemyType.__CastFrom('Normal'))

print(CS.EnemyType.Normal == CS.EnemyType.__CastFrom('Normal'))

C#:

[LuaCallCSharp]
public enum EnemyType
{
    Easy,
    Normal,
    Hard
}

8.Delegate

C#:

public Action<string> TestDelegate = (param) =>
{
    Debug.Log("TestDelegate in c#:" + param);
};

lua:

testobj.TestDelegate('hello') --直接调用
local function lua_delegate(str)
    print('TestDelegate in lua:', str)
end

--combine,这里演示的是C#delegate作为右值,左值也支持
testobj.TestDelegate = lua_delegate + testobj.TestDelegate 
testobj.TestDelegate('hello')
testobj.TestDelegate = testobj.TestDelegate - lua_delegate --remove
testobj.TestDelegate('hello')

9.Event事件

比如testobj类里头有个事件定义是这样:

public event Action TestEvent;

在xlua中增加事件回调

testobj:TestEvent('+', lua_event_callback)

在xlua中移除事件回调

testobj:TestEvent('-', lua_event_callback)

例子:

C#:

public event Action TestEvent;

lua:

--事件
local function lua_event_callback1() print('lua_event_callback1') end
local function lua_event_callback2() print('lua_event_callback2') end
testobj:TestEvent('+', lua_event_callback1)
testobj:CallEvent()
testobj:TestEvent('+', lua_event_callback2)
testobj:CallEvent()
testobj:TestEvent('-', lua_event_callback1)
testobj:CallEvent()
testobj:TestEvent('-', lua_event_callback2)

10.操作符

lua:

local testobj2 = DerivedClass()
testobj2.DMF = 2048
print('(testobj + testobj2).DMF = ', (testobj + testobj2).DMF)

C#

//重写“+”号
public static DerivedClass operator +(DerivedClass a, DerivedClass b)
{
    DerivedClass ret = new DerivedClass();
    ret.DMF = a.DMF + b.DMF;
    return ret;
}

11.Extension methods

lua:

print(testobj:GetSomeData())
print(testobj:GetSomeBaseData()) --访问基类的Extension methods
testobj:GenericMethodOfString()  --通过Extension methods实现访问泛化方法

C#:

[LuaCallCSharp]
public static class DerivedClassExtensions
{
    public static int GetSomeData(this DerivedClass obj)
    {
        Debug.Log("GetSomeData ret = " + obj.DMF);
        return obj.DMF;
    }

    public static int GetSomeBaseData(this BaseClass obj)
    {
        Debug.Log("GetSomeBaseData ret = " + obj.BMF);
        return obj.BMF;
    }

    public static void GenericMethodOfString(this DerivedClass obj)
    {
        obj.GenericMethod<string>();
    }
}

12.cast类型转换

有的时候第三方库对外暴露的是一个interface或者抽象类,实现类是隐藏的,这样我们无法对实现类进行代码生成。该实现类将会被xlua识别为未生成代码而用反射来访问,如果这个调用是很频繁的话还是很影响性能的,这时我们就可以把这个interface或者抽象类加到生成代码,然后指定用该生成代码来访问:

    cast(calc, typeof(CS.Tutorial.Calc))

上面就是指定用CS.Tutorial.Calc的生成代码来访问calc对象。

--cast
local calc = testobj:GetCalc()
print('assess instance of InnerCalc via reflection', calc:add(1, 2))
cast(calc, typeof(CS.Tutorial.ICalc))
print('cast to interface ICalc', calc:add(1, 2))

C# 

public interface ICalc
{
    int add(int a, int b);
}

class InnerCalc : ICalc
{
    public int add(int a, int b)
    {
         return a + b;
    }

    public int id = 100;
}

public ICalc GetCalc()
{
     return new InnerCalc();
}

13.静态函数和成员函数的区别

成员函数会加一个self参数,这个self是C#对象本身(对应C#的this)

静态函数:由类调用,必须要用点号调用,否则会报错。

成员函数:由对象调用,用冒号调用(推荐),或用点号调用,在函数的第一个参数传入self

14.List在Lua中的调用

local list = CS.System.Collections.Generic['List`1[System.String]']

list:Add("123")

--输出, 索引下标到list.Count - 1,否则会数组越界。

for i = 0, list.Count - 1 do

CS.UnityEngine.Debug(list[i])

end

例如,Unity中的Transform集合,List<Transform>可以这样表示

CS.System.Collections.Generic['List`1[UnityEngine.Transform]']

三.注意事项

1.在lua端,调用Random方法,会调用float参数的重载,如果需要使用随机int类型的数值,需要调用Floor向下取整,或者CS.System.Convert.ToInt32()方法

CS.UnityEngine.Mathf.Floor(CS.UnityEngine.Random.Range(0, 10))

2.在lua中,不需要new Vector3(0,0,0),直接CS.UnityEngine.Vector3(0,0,0)

3.在Monobehaviour中,Invoke方法,在C#实际上是this.Invoke(),在lua使用时,需要self:Invoke()来调用

4.在lua只有number一种数值类型,所以在C#中0.7f的float类型,数值中f需要去掉。

5.调用成员函数,需要使用冒号调用,或者使用点号在第一个参数中传入self

6.gameObject.GetComponent('Text')

7.已经Destroy的GameObject,其实那C#对象并不为null,是UnityEngine.Object重载的==操作符。当一个对象被Destroy,未初始化等情况,obj == null返回true,但这C#对象并不为null,可以通过System.Object.ReferenceEquals(null, obj)来验证下。所以,当一个对象被Destroy,在判断这个对象是否为空时,不要使用System.Object.ReferenceEquals(null, obj)。

8.从lua传递参数到C#的一个object参数,需要使用CS.XLua.Cast.Int32(1234)。正常类型的参数,使用CS.System.Convert.ToInt32(1234)等转换方法,传递参数即可。

public static void PrintType(object o)
{
    Debug.Log("type:" + o.GetType() + ", value:" + o);
}

//直接传1234到一个object参数,xLua将选择能保留最大精度的long来传递
luaenv.DoString("CS.XLuaTest.RawObjectTest.PrintType(1234)");

//通过一个继承RawObject的类,能实现指明以一个int来传递
//尝试使用CS.System.Convert.ToInt32(1234)传递参数,接收到的参数还是long类型
luaenv.DoString("CS.XLuaTest.RawObjectTest.PrintType(CS.XLua.Cast.Int32(1234))");

四.误区

误区1:我哪里预测得到哪些地方有bug,进而打标签呢?

典型的打开方式是上线前把几乎所有类型都配置上,然后随着后续迭代把一些稳定的模块排除在外。

误区2:打标签太繁琐了,操作性不强

xLua支持的动态配置结合linq,批量配置大量类。如果你没规划名字空间,可以考虑全注入+排除某些类的方式。还可以考虑放到一个目录,然后正则处理后生成一个类的静态列表(xLua的另外一种配置方式)。

误区3:Hotfix列表里头的类型都加到LuaCallCSharp列表。

这样操作会大大增加代码大小。其实没必要加,业务代码是不加都能调用到的。

误区4:希望用lua函数做callback,但对应的委托没加到CSharpCallLua。

这个有个通用的解决办法:CSharpCallLua也支持动态配置,可以反射结合linq,返回所有字段,所有函数的参数和返回值涉及到的委托类型

误区5:lua打完补丁,lua补丁怎么维护?

lua补丁其实只是紧急情况下(影响面大的bug)紧急处理方案,正常情况下补丁就修当前线上版本的bug而已,后续不需要维护。

 

五、xLua官方案例

1.CSCallLua.cs

using System;
using System.Collections.Generic;
using UnityEngine;
using XLua;

public class CSCallLua : MonoBehaviour
{
    LuaEnv luaenv = null;
    string script = @"
        a = 1
        b = 'hello world'
        c = true

        d = {
           f1 = 12, f2 = 34, 
           1, 2, 3,
           add = function(self, a, b) 
              print('d.add called')
              return a + b 
           end
        }

        function e()
            print('i am e')
        end

        function f(a, b)
            print('a', a, 'b', b)
            return 1, {f1 = 1024}
        end
        
        function ret_e()
            print('ret_e called')
            return e
        end
    ";

    public class DClass
    {
        public int f1;
        public int f2;
    }

    [CSharpCallLua]
    public interface ItfD
    {
        int f1 { get; set; }
        int f2 { get; set; }
        int add(int a, int b);
    }

    [CSharpCallLua]
    public delegate int FDelegate(int a, string b, out DClass c);

    [CSharpCallLua]
    public delegate Action GetE();

    // Use this for initialization
    void Start()
    {
        luaenv = new LuaEnv();
        luaenv.DoString(script);

        Debug.Log("_G.a = " + luaenv.Global.Get<int>("a"));
        Debug.Log("_G.b = " + luaenv.Global.Get<string>("b"));
        Debug.Log("_G.c = " + luaenv.Global.Get<bool>("c"));


        DClass d = luaenv.Global.Get<DClass>("d");//映射到有对应字段的class,by value
        Debug.Log("_G.d = {f1=" + d.f1 + ", f2=" + d.f2 + "}");

        Dictionary<string, double> d1 = luaenv.Global.Get<Dictionary<string, double>>("d");//映射到Dictionary<string, double>,by value
        Debug.Log("_G.d = {f1=" + d1["f1"] + ", f2=" + d1["f2"] + "}, d.Count=" + d1.Count);

        List<double> d2 = luaenv.Global.Get<List<double>>("d"); //映射到List<double>,by value
        Debug.Log("_G.d.len = " + d2.Count);

        ItfD d3 = luaenv.Global.Get<ItfD>("d"); //映射到interface实例,by ref,这个要求interface加到生成列表,否则会返回null,建议用法
        d3.f2 = 1000;
        Debug.Log("_G.d = {f1=" + d3.f1 + ", f2=" + d3.f2 + "}");
        Debug.Log("_G.d:add(1, 2)=" + d3.add(1, 2));

        LuaTable d4 = luaenv.Global.Get<LuaTable>("d");//映射到LuaTable,by ref
        Debug.Log("_G.d = {f1=" + d4.Get<int>("f1") + ", f2=" + d4.Get<int>("f2") + "}");


        Action e = luaenv.Global.Get<Action>("e");//映射到一个delgate,要求delegate加到生成列表,否则返回null,建议用法
        e();

        FDelegate f = luaenv.Global.Get<FDelegate>("f");
        DClass d_ret;
        int f_ret = f(100, "John", out d_ret);//lua的多返回值映射:从左往右映射到c#的输出参数,输出参数包括返回值,out参数,ref参数
        Debug.Log("ret.d = {f1=" + d_ret.f1 + ", f2=" + d_ret.f2 + "}, ret=" + f_ret);

        GetE ret_e = luaenv.Global.Get<GetE>("ret_e");//delegate可以返回更复杂的类型,甚至是另外一个delegate
        e = ret_e();
        e();

        LuaFunction d_e = luaenv.Global.Get<LuaFunction>("e");
        d_e.Call();

    }

    // Update is called once per frame
    void Update()
    {
        if (luaenv != null)
        {
            luaenv.Tick();
        }
    }

    void OnDestroy()
    {
        luaenv.Dispose();
    }
}

2.LuaCallCs.cs

using System;
using UnityEngine;
using XLua;

namespace Tutorial
{
    [LuaCallCSharp]
    public class BaseClass
    {
        public static void BSFunc()
        {
            Debug.Log("Derived Static Func, BSF = " + BSF);
        }

        public static int BSF = 1;

        public void BMFunc()
        {
            Debug.Log("Derived Member Func, BMF = " + BMF);
        }

        public int BMF { get; set; }
    }

    public struct Param1
    {
        public int x;
        public string y;
    }

    [LuaCallCSharp]
    public enum TestEnum
    {
        E1,
        E2
    }

    [LuaCallCSharp]
    public class PrivateOverrideClass
    {
        public void TestFunc(string i)
        {
            Debug.Log("TestFunc(string i), i = " + i);
        }

        private void TestFunc(double i)
        {
            Debug.Log("TestFunc(double i), i = " + i);
        }

        public void TestFunc3(int i)
        {
            Debug.Log("TestFunc(int i), i = " + i);
        }

        public void TestFunc2(string i)
        {
            Debug.Log("TestFunc(string i), i = " + i);
        }

        private void TestFunc2(double i)
        {
            Debug.Log("TestFunc(double i), i = " + i);
        }
    }

    [LuaCallCSharp]
    public class DerivedClass : BaseClass
    {
        [LuaCallCSharp]
        public enum TestEnumInner
        {
            E3,
            E4
        }

        public void DMFunc()
        {
            Debug.Log("Derived Member Func, DMF = " + DMF);
        }

        public int DMF { get; set; }

        public double ComplexFunc(Param1 p1, ref int p2, out string p3, Action luafunc, out Action csfunc)
        {
            Debug.Log("P1 = {x=" + p1.x + ",y=" + p1.y + "},p2 = " + p2);
            luafunc();
            p2 = p2 * p1.x;
            p3 = "hello " + p1.y;
            csfunc = () =>
            {
                Debug.Log("csharp callback invoked!");
            };
            return 1.23;
        }

        public void TestFunc(int i)
        {
            Debug.Log("TestFunc(int i)");
        }

        public void TestFunc(string i)
        {
            Debug.Log("TestFunc(string i)");
        }

        public static DerivedClass operator +(DerivedClass a, DerivedClass b)
        {
            DerivedClass ret = new DerivedClass();
            ret.DMF = a.DMF + b.DMF;
            return ret;
        }

        public void DefaultValueFunc(int a = 100, string b = "cccc", string c = null)
        {
            Debug.Log("DefaultValueFunc: a=" + a + ",b=" + b + ",c=" + c);
        }

        public void VariableParamsFunc(int a, params string[] strs)
        {
            Debug.Log("VariableParamsFunc: a =" + a);
            foreach (var str in strs)
            {
                Debug.Log("str:" + str);
            }
        }

        public TestEnum EnumTestFunc(TestEnum e)
        {
            Debug.Log("EnumTestFunc: e=" + e);
            return TestEnum.E2;
        }

        public Action<string> TestDelegate = (param) =>
        {
            Debug.Log("TestDelegate in c#:" + param);
        };

        public event Action TestEvent;

        public void CallEvent()
        {
            TestEvent();
        }

        public ulong TestLong(long n)
        {
            return (ulong)(n + 1);
        }

        class InnerCalc : ICalc
        {
            public int add(int a, int b)
            {
                return a + b;
            }

            public int id = 100;
        }

        public ICalc GetCalc()
        {
            return new InnerCalc();
        }

        public void GenericMethod<T>()
        {
            Debug.Log("GenericMethod<" + typeof(T) + ">");
        }
    }

    [LuaCallCSharp]
    public interface ICalc
    {
        int add(int a, int b);
    }

    [LuaCallCSharp]
    public static class DerivedClassExtensions
    {
        public static int GetSomeData(this DerivedClass obj)
        {
            Debug.Log("GetSomeData ret = " + obj.DMF);
            return obj.DMF;
        }

        public static int GetSomeBaseData(this BaseClass obj)
        {
            Debug.Log("GetSomeBaseData ret = " + obj.BMF);
            return obj.BMF;
        }

        public static void GenericMethodOfString(this DerivedClass obj)
        {
            obj.GenericMethod<string>();
        }
    }
}

public class LuaCallCs : MonoBehaviour
{
    LuaEnv luaenv = null;
    string script = @"
        function demo()
            --new C#对象
            local newGameObj = CS.UnityEngine.GameObject()
            local newGameObj2 = CS.UnityEngine.GameObject('helloworld')
            print(newGameObj, newGameObj2)
        
            --访问静态属性,方法
            local GameObject = CS.UnityEngine.GameObject
            print('UnityEngine.Time.deltaTime:', CS.UnityEngine.Time.deltaTime) --读静态属性
            CS.UnityEngine.Time.timeScale = 0.5 --写静态属性
            print('helloworld', GameObject.Find('helloworld')) --静态方法调用

            --访问成员属性,方法
            local DerivedClass = CS.Tutorial.DerivedClass
            local testobj = DerivedClass()
            testobj.DMF = 1024--设置成员属性
            print(testobj.DMF)--读取成员属性
            testobj:DMFunc()--成员方法

            --基类属性,方法
            print(DerivedClass.BSF)--读基类静态属性
            DerivedClass.BSF = 2048--写基类静态属性
            DerivedClass.BSFunc();--基类静态方法
            print(testobj.BMF)--读基类成员属性
            testobj.BMF = 4096--写基类成员属性
            testobj:BMFunc()--基类方法调用

            --复杂方法调用
            local ret, p2, p3, csfunc = testobj:ComplexFunc({x=3, y = 'john'}, 100, function()
               print('i am lua callback')
            end)
            print('ComplexFunc ret:', ret, p2, p3, csfunc)
            csfunc()

           --重载方法调用
           testobj:TestFunc(100)
           testobj:TestFunc('hello')
		   
		   --xlua.private_accessible访问私有方法
		   local PrivateOverrideClass = CS.Tutorial.PrivateOverrideClass
		   local priObj=PrivateOverrideClass()
		   priObj:TestFunc(100.0)
	       priObj:TestFunc('hello')
		   xlua.private_accessible(PrivateOverrideClass);
		   priObj:TestFunc(100.0)
		   priObj:TestFunc('hello')

           --操作符
           local testobj2 = DerivedClass()
           testobj2.DMF = 2048
           print('(testobj + testobj2).DMF = ', (testobj + testobj2).DMF)

           --默认值
           testobj:DefaultValueFunc(1)
           testobj:DefaultValueFunc(3, 'hello', 'john')

           --可变参数
           testobj:VariableParamsFunc(5, 'hello', 'john')

           --Extension methods
           print(testobj:GetSomeData()) 
           print(testobj:GetSomeBaseData()) --访问基类的Extension methods
           testobj:GenericMethodOfString()  --通过Extension methods实现访问泛化方法

           --枚举类型
           local e = testobj:EnumTestFunc(CS.Tutorial.TestEnum.E1)
           print(e, e == CS.Tutorial.TestEnum.E2)
           print(CS.Tutorial.TestEnum.__CastFrom(1), CS.Tutorial.TestEnum.__CastFrom('E1'))
           print(CS.Tutorial.DerivedClass.TestEnumInner.E3)
           assert(CS.Tutorial.BaseClass.TestEnumInner == nil)

           --Delegate
           testobj.TestDelegate('hello') --直接调用
           local function lua_delegate(str)
               print('TestDelegate in lua:', str)
           end
           testobj.TestDelegate = lua_delegate + testobj.TestDelegate --combine,这里演示的是C#delegate作为右值,左值也支持
           testobj.TestDelegate('hello')
           testobj.TestDelegate = testobj.TestDelegate - lua_delegate --remove
           testobj.TestDelegate('hello')

           --事件
           local function lua_event_callback1() print('lua_event_callback1') end
           local function lua_event_callback2() print('lua_event_callback2') end
           testobj:TestEvent('+', lua_event_callback1)
           testobj:CallEvent()
           testobj:TestEvent('+', lua_event_callback2)
           testobj:CallEvent()
           testobj:TestEvent('-', lua_event_callback1)
           testobj:CallEvent()
           testobj:TestEvent('-', lua_event_callback2)

           --64位支持
           local l = testobj:TestLong(11)
           print(type(l), l, l + 100, 10000 + l)

           --typeof
           newGameObj:AddComponent(typeof(CS.UnityEngine.ParticleSystem))

           --cast
           local calc = testobj:GetCalc()
           print('assess instance of InnerCalc via reflection', calc:add(1, 2))
           assert(calc.id == 100)
           cast(calc, typeof(CS.Tutorial.ICalc))
           print('cast to interface ICalc', calc:add(1, 2))
           assert(calc.id == nil)
       end

       demo()

       --协程下使用
       --local co = coroutine.create(function()
           --print('------------------------------------------------------')
           --demo()
       --end)
       --assert(coroutine.resume(co))
    ";

    // Use this for initialization
    void Start()
    {
        luaenv = new LuaEnv();
        luaenv.DoString(script);
    }

    // Update is called once per frame
    void Update()
    {
        if (luaenv != null)
        {
            luaenv.Tick();
        }
    }

    void OnDestroy()
    {
        luaenv.Dispose();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值