XLua教程之C#调用Lua

发布于:2025-09-15 ⋅ 阅读:(15) ⋅ 点赞:(0)

上一篇文章

XLua教程之入门篇-CSDN博客

在C#脚本中访问lua全局数据,特别是table以及function,代价比较大,建议尽量少做相关操作。

LuaEnv.Global.Get

用于获取一个全局变量,但是无法获取局部变量(用local修饰)

全局基本类型变量

支持int、float、double、bool、string类型

string value1 = luaenv.Global.Get<string>("stringValue");
Debug.Log($"string:{value1}");

float value2 = luaenv.Global.Get<float>("floatValue");
Debug.Log($"float:{value2}");

bool value3 = luaenv.Global.Get<bool>("boolValue");
Debug.Log($"bool:{value3}");

double value4 = luaenv.Global.Get<double>("doubleValue");
Debug.Log($"double:{value4}");

int value5 = luaenv.Global.Get<int>("intValue");
Debug.Log($"int:{value5}");

全局函数

测试:Lua脚本侧代码

--无参无返回值
function SayHi()
    print("hello world!")
end

--有参有返回值
function GetNumSum(a,b,c)
    local result = a+b+c;
    print(result)
    return result
end

--变长参数多返回值
function GetManyResult(...)
    local list = {...}
    local result1 = 0;
    for _,v in ipairs(list) do
        result1 = result1 + v
    end
    local result2 = 1;
    for _,v in ipairs(list) do
        result2 = result2 * v
    end
    return result1,result2
end

第一种方法  映射到委托delegate(推荐使用)

这种是建议的方式,性能好很多,而且类型安全。缺点是要生成代码(如果没生成代码会抛InvalidCastException异常)

1、先注册对应Lua函数的C#委托,并添加 [CSharpCallLua]标签。(无参无返回值可以不用添加该标签,xlua默认支持)

//无参无返回值
public delegate void NoParamNoReturn();

//有参有返回值
[CSharpCallLua]
public delegate int XParamOneReturn(int a,int b,int c);

//变长参数1返回值
[CSharpCallLua]
public delegate int XParam1Return(params int[] temp);

2、先清空生成的xlua插桩代码,再重新生成

3、调用

//无参无返回值
NoParamNoReturn func1 = luaEnv.Global.Get<NoParamNoReturn>("SayHi");
func1();

//有参有返回值
XParamOneReturn func2 = luaEnv.Global.Get<XParamOneReturn>("GetNumSum");
var result1 = func2(1,2,3);
Debug.Log(result1);

//变长参数1返回值
XParam1Return func3 = luaEnv.Global.Get<XParam1Return>("GetManyResult1"); 
int a =default(int);
int b =default(int);
var result2 = func3(1,2,3,4);
Debug.Log(result2);

第二种方法  映射到LuaFunction

LuaFunction上有个变参的Call函数,可以传任意类型,任意个数的参数,返回值是object的数组,对应于lua的多返回值。

//无参无返回值
LuaFunction func1 = luaEnv.Global.Get<LuaFunction>("SayHi");
func1.Call();

//有参有返回值
LuaFunction func2 = luaEnv.Global.Get<LuaFunction>("GetNumSum");
var result1 = func2.Call(1,2,3);
foreach (var item in result1)
{
    Debug.Log(item);
}

//变长参数多返回值
LuaFunction func3 = luaEnv.Global.Get<LuaFunction>("GetManyResult");
var result2 = func3.Call(1,2,3);
foreach (var item in result2)
{
    Debug.Log(item);
}

对比:

优先使用映射到委托方案

映射到XLua自带的LuaFunction,简单方便,但是会消耗性能;

映射到Delegate委托,官方建议,性能比LuaFunction要好很多,而且类型安全;但需要在自定义委托前添加[CSharpCallLua]特性标签

特性 映射到委托 (Delegate) 映射到 LuaFunction
性能 极高 (接近原生C#调用) 较低 (涉及查找、压参、调用、返回等一系列开销)
用法 像调用普通C#委托一样 调用其 Call(...) 方法,传入参数数组
类型安全 强类型,编译时检查参数和返回值类型 弱类型,参数和返回值都是 object[],运行时易出错
内存开销 较大(每次调用可能产生临时 object[] 垃圾)
适用场景 高频调用(如 Update、UI事件回调) 低频调用一次性调用参数数量/类型不固定
配置要求 需要标记 [CSharpCallLua] 并生成代码 无需任何额外配置,开箱即用

全局表

根据表的数据结构类型可以按照不同的情况,选择不同的映射形式。

如果表的形式类似于列表,可以映射到C#的List<T>。

如果表的形式类似于字典,可以映射到C#的Dictionary<T>。

如果表的形式类似于类,可以映射到C#的class。

映射到List<T>

List<int> list1 = luaEnv.Global.Get<List<int>>("list1");
foreach (var item in list1)
{
    Debug.Log(item);
}

映射到Dictionary<T>

Dictionary<int, string> dic = luaEnv.Global.Get<Dictionary<int, string>>("list2");
foreach (var item in dic)
{
    Debug.Log($"{item.Key}:{item.Value}");
}

映射到class

先根据lua表,声明对应C#类结构,再调用

public class Student
{
    public int id;
    public string name;
    public bool sex;
    public float score;
}

Student student = luaEnv.Global.Get<Student>("Student");
Debug.Log($"{student.id} {student.name} {student.sex} {student.score}");

映射到LuaTable

xLua自带映射,兼容Lua表多种情况,不用定义c#类结构,开箱即用。但是性能消耗比较大,一般情况不推荐使用。

LuaTable student = luaEnv.Global.Get<LuaTable>("Student");
Debug.Log($"{student.Get<int>("id")}");
Debug.Log($"{student.Get<string>("name")}");
Debug.Log($"{student.Get<bool>("sex")}");
Debug.Log($"{student.Get<float>("score")}");

LuaEnv.Global.Set

用于修改一个全局变量

//string
luaenv.Global.Set("stringValue", "天天向上");
//float
luaenv.Global.Set("floatValue", 99.99);
//bool
luaenv.Global.Set("boolValue", false);
//double
luaenv.Global.Set("doubleValue", 9.999999999);
//int
luaenv.Global.Set("intValue", 438);