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

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

在Lua中new C#对象

例如创建GameObject

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

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

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

创建对象:

local newGo = CS.UnityEngine.GameObject();

local newGo = CS.UnityEngine.GameObject('name')

访问静态属性:

CS.UnityEngine.Time.deltaTime

CS.UnityEngine.Time.timeScale = 0.5

访问静态方法:

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

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

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

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

访问成员属性:. 运算符

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

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

local cameraComponent = camera.GetComponent(camera, "Camera")

local cameraComponent = camera:GetComponent("Camera")

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

带有结构体的参数的方法

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

public struct MyStruct
{
     public string x;
     public string y;
}

public void CSharpFunc(MyStruct p)
{
     Debug.Log(p.x);
     Debug.Log(p.y);
}

--lua
myStructTable={x="C#",y="lua"}
obj:CSharpFunc(myStructTable)

调用C#泛型方法

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

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

[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>();
	}
}           


print(testobj:GetSomeData()) 
print(testobj:GetSomeBaseData()) --访问基类的Extension methods
testobj: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)

function IsNull( obj )
	if obj==nil or obj:Equals(nil) then
		return true;
	end
	return false;
end

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

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

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

3、if not xxif ~ xxx

C:\Users\15291>lua
Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio
> a = false
> b = true
> print((a and b))
false
> print((a or b))
true
> if not (nil and a) then print("xx") end
xx
> if not nil and a then print("xx") end
>
>