Xlua学习笔记(Lua调用C#及踩坑)

XLua是目前国内使用较多的热更新框架(可能是有腾讯加持), Xlua同时也提供了Lua调用C#的能力,其实Lua调用C#的场景更多,要想实现热更新,很多控制逻辑都得写在Lua里,这篇文章主要是记录了Lua如何调用C#,以及踩过的一些坑。

在Lua中new C#对象

例如创建GameObject

1print("Lua call C# start...")
2CS.UnityEngine.GameObject()
3-- 指定GameObject的名称
4CS.UnityEngine.GameObject("NewByLua")

Lua访问静态属性、静态方法

记得最好设置本地Local变量,提高性能

 1创建对象:
 2
 3local newGo = CS.UnityEngine.GameObject();
 4
 5local newGo = CS.UnityEngine.GameObject('name')
 6
 7访问静态属性:
 8
 9CS.UnityEngine.Time.deltaTime
10
11CS.UnityEngine.Time.timeScale = 0.5
12
13访问静态方法:
14
15CS.UnityEngine.GameObject.Find('name')

小技巧:如果有一些需要经常访问的类,可以用局部变量引用后,通过局部变量进行访问,可以提高性能

1local GameObject = CS.UnityEngine.GameObject
2GameObject.Find('name')

Lua中访问C#成员变量和方法

访问成员属性:. 运算符

1local camera = CS.UnityEngine.GameObject.Find("Main Camera")
2camera.name = "newName";

访问成员方法:. 运算符或 :语法糖

1local cameraComponent = camera.GetComponent(camera, "Camera")
2
3local cameraComponent = camera:GetComponent("Camera")

注意:在Lua中没有this关键字,所以如果使用 . ,则需要在方法中手动传递对象本身;如果使用:则不需要

带有结构体的参数的方法

在lua端定义一个表去映射结构体:

 1public struct MyStruct
 2{
 3     public string x;
 4     public string y;
 5}
 6
 7public void CSharpFunc(MyStruct p)
 8{
 9     Debug.Log(p.x);
10     Debug.Log(p.y);
11}
12
13--lua
14myStructTable={x="C#",y="lua"}
15obj:CSharpFunc(myStructTable)

调用C#泛型方法

lua中不支持C#的泛型方法,但可以使用扩展方法来调用

 1public void GenericMethod<T>()
 2{
 3	Debug.Log("GenericMethod<" + typeof(T) + ">");
 4}
 5
 6[LuaCallCSharp]
 7public static class DerivedClassExtensions
 8{
 9	public static int GetSomeData(this DerivedClass obj)
10	{
11		Debug.Log("GetSomeData ret = " + obj.DMF);
12		return obj.DMF;
13	}
14
15	public static int GetSomeBaseData(this BaseClass obj)
16	{
17		Debug.Log("GetSomeBaseData ret = " + obj.BMF);
18		return obj.BMF;
19	}
20
21	public static void GenericMethodOfString(this DerivedClass obj)
22	{
23		obj.GenericMethod<string>();
24	}
25}           
26
27
28print(testobj:GetSomeData()) 
29print(testobj:GetSomeBaseData()) --访问基类的Extension methods
30testobj:GenericMethodOfString()  --通过Extension methods实现访问泛化方法

Lua访问C#的其他注意事项:

Lua调用C#,需要在Xlua中生成"适配代码",则在这个类打入一个[LuaCallCsharp]的标签。

实际开发过程中,lua调用C#用的比较多。

在标有[XLua.LuaCallCsharp]的C#类中,添加新的方法后,如果是生成了代码类,则必须重新生成或者删除,否则XLua用以前生成的,进行注册查询,会出现Lua异常

Lua语言踩坑

这部分内容是7.27 号补充

1、Lua中的nil和C#中的null不能同等比较!

之前遇到个BUG,偶现报空指针,原来才发现Lua中的nil和C#中的null不能同等比较。Lua中依旧存在引用关系,但是C# 里这个对象已经被销毁了,根据原有的业务逻辑,所以需要两次判空才可以。

基于这种状况有两种解决方式:

第一种就是双重判断,obj==nil or obj:Equals(nil)

1function IsNull( obj )
2	if obj==nil or obj:Equals(nil) then
3		return true;
4	end
5	return false;
6end

第二种就是C#提供判空方法:

 1[XLua.LuaCallCSharp]
 2public static class MyObj
 3{
 4    /// <summary>
 5    /// 扩展一个Object判空的方法,主要是给lua使用,lua没法用nil和null进行比较
 6    /// </summary>
 7    /// <param name="obj"></param>
 8    /// <returns></returns>
 9    public static bool IsNull(this Object obj)
10    {
11        return obj == null;
12    }
13}

2、Lua数组索引从1开始;

3、if not xxif ~ xxx

 1C:\Users\15291>lua
 2Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio
 3> a = false
 4> b = true
 5> print((a and b))
 6false
 7> print((a or b))
 8true
 9> if not (nil and a) then print("xx") end
10xx
11> if not nil and a then print("xx") end
12>
13>