【XLua】020-Lua访问C#:其他使用说明


其他的使用

其他的使用方式参见官方实例如下:

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

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

        public static int BSF = 1;

        public void BMFunc()
        {
            Debug.Log("Driven 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 DrivenClass : BaseClass
    {
        [LuaCallCSharp]
        public enum TestEnumInner
        {
            E3,
            E4
        }

        public void DMFunc()
        {
            Debug.Log("Driven 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 DrivenClass operator +(DrivenClass a, DrivenClass b)
        {
            DrivenClass ret = new DrivenClass();
            ret.DMF = a.DMF + b.DMF;
            return ret;
        }

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

        public void VariableParamsFunc(int a, params string[] strs)
        {
            UnityEngine.Debug.Log("VariableParamsFunc: a =" + a);
            foreach (var str in strs)
            {
                UnityEngine.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 DrivenClassExtensions
    {
        public static int GetSomeData(this DrivenClass 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 DrivenClass 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 DrivenClass = CS.Tutorial.DrivenClass
            local testobj = DrivenClass()
            testobj.DMF = 1024--设置成员属性
            print(testobj.DMF)--读取成员属性
            testobj:DMFunc()--成员方法

            --基类属性,方法
            print(DrivenClass.BSF)--读基类静态属性
            DrivenClass.BSF = 2048--写基类静态属性
            DrivenClass.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')

           --操作符
           local testobj2 = DrivenClass()
           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.DrivenClass.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();
    }
}

其他使用方式的文档说明:


  • 操作符

支持的操作符有:+,-,*,/,==,一元-,<,<=, %,[]


  • 参数带默认值的方法

和C#调用有默认值参数的函数一样,如果所给的实参少于形参,则会用默认值补上。


  • 可变参数方法

对于C#的如下方法:
void VariableParamsFunc(int a, params string[] strs)
可以在lua里头这样调用:
testobj:VariableParamsFunc(5, 'hello', 'john')
使用Extension methods
在C#里定义了,lua里就能直接使用。


  • 泛化(模版)方法

不直接支持,可以通过Extension methods功能进行封装后调用。


  • 枚举类型

枚举值就像枚举类型下的静态属性一样。
testobj:EnumTestFunc(CS.Tutorial.TestEnum.E1)
上面的EnumTestFunc函数参数是Tutorial.TestEnum类型的
另外,如果枚举类加入到生成代码的话,枚举类将支持__CastFrom方法,可以实现从一个整数或者字符串到枚举值的转换,例如:
CS.Tutorial.TestEnum.__CastFrom(1)
CS.Tutorial.TestEnum.__CastFrom('E1')


  • delegate使用(调用,+,-)

C#的delegate调用:和调用普通lua函数一样
+操作符:对应C#的+操作符,把两个调用串成一个调用链,右操作数可以是同类型的C# delegate或者是lua函数。
-操作符:和+相反,把一个delegate从调用链中移除。
Ps:delegate属性可以用一个luafunction来赋值。


  • event

比如testobj里头有个事件定义是这样:public event Action TestEvent;
增加事件回调
testobj:TestEvent('+', lua_event_callback)
移除事件回调
testobj:TestEvent('-', lua_event_callback)


  • 64位整数支持

Lua53版本64位整数(long,ulong)映射到原生的64未整数,而luaji版本t,相当于lua5.1的标准,本身不支持64位,xlua做了个64位支持的扩展库,C#的long和ulong都将映射到userdata:
1、支持在lua里头进行64位的运算,比较,打印
2、支持和lua number的运算,比较
3、要注意的是,在64扩展库中,实际上只有int64,ulong也会先强转成long再传递到lua,而对ulong的一些运算,比较,我们采取和java一样的支持方式,提供一组API,详情请看API文档。


  • C#复杂类型和table的自动转换

对于一个有无参构造函数的C#复杂类型,在lua侧可以直接用一个table来代替,该table对应复杂类型的public字段有相应字段即可,支持函数参数传递,属性赋值等,例如:
C#下B结构体(class也支持)定义如下:

public struct A
{
    public int a;
}

public struct B
{
    public A b;
    public double c;
}

某个类有成员函数如下:
void Foo(B b)
在lua可以这么调用
obj:Foo({b = {a = 100}, c = 200})


  • 获取类型(相当于C#的typeof)

比如要获取UnityEngine.ParticleSystem类的Type信息,可以这样
typeof(CS.UnityEngine.ParticleSystem)


  • “强”转

lua没类型,所以不会有强类型语言的“强转”,但有个有点像的东西:告诉xlua要用指定的生成代码去调用一个对象,这在什么情况下能用到呢?有的时候第三方库对外暴露的是一个interface或者抽象类,实现类是隐藏的,这样我们无法对实现类进行代码生成。该实现类将会被xlua识别为未生成代码而用反射来访问,如果这个调用是很频繁的话还是很影响性能的,这时我们就可以把这个interface或者抽象类加到生成代码,然后指定用该生成代码来访问:
cast(calc, typeof(CS.Tutorial.Calc))
上面就是指定用CS.Tutorial.Calc的生成代码来访问calc对象。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容