核心知识点:Lua 访问 C# 类 / 对象 / 组件、cs 命名空间前缀、对象创建、GameObject 查找获取组件、属性读写、重载函数坑点、可变参数、委托与多播委托、事件注册移除、桥接 (Gen) 文件、虚拟栈交互底层原理
一、Lua 访问 C# 基础规则
1 概念
Lua 脚本访问 C# 的类、静态成员、实例对象,必须加cs.前缀;对应 C# 完整命名空间;Lua 没有new关键字,直接调用类名()创建 C# 对象实例。
2 特性 & 规则
-
访问格式:
cs.命名空间.类名;如cs.UnityEngine.GameObject -
创建 C# 对象:
local obj = cs.UnityEngine.GameObject(),不用 new; -
调用实例成员方法 用冒号
:,会自动隐式传入 self(对象实例); -
调用静态成员方法 用点
.,不需要 self; -
获取组件、Transform、Time.timeScale 这类属性可以直接读写。
3 语法 & 代码片段
-- 创建GameObject
local go = cs.UnityEngine.GameObject("测试物体")
-- 查找物体
local cube = cs.UnityEngine.GameObject.Find("Cube")
-- 获取组件,冒号调用实例方法
local boxColl = cube:GetComponent(cs.UnityEngine.BoxCollider)
-- 读写组件属性
boxColl.size = cs.UnityEngine.Vector3(5,1,1)
-- 读写静态属性时间缩放
cs.UnityEngine.Time.timeScale = 0.5
4 相关知识点对比
.点号 VS :冒号
静态:.,无 self; 实例方法::,自动把调用对象作为 self 传入第一个参数。
5 模块拓展
Vector3/Quaternion 等结构体同样用 cs. 前缀构造。
二、Lua 访问 C# 类:实例、静态、继承
1 概念
Lua 可以创建 C# 类实例;访问实例成员、静态成员;子类对象可以直接访问继承自父类的成员,遵循 C# 继承规则。
2 特性 & 规则
-
实例对象:
local obj = cs.命名空间.类名(); -
实例成员(字段 / 属性 / 实例函数):冒号调用;
-
静态成员(static):类名
.直接访问,不需要实例; -
子类实例可以直接访问父类公开成员,和 C# 行为保持一致。
3 语法 & 代码片段
-- 创建子类实例
local testObj = cs.MyNamespace.ChildClass()
-- 读写实例属性
testObj.dmf = 123
-- 调用实例方法
testObj:DMFFunc()
-- 访问继承自父类的成员
testObj.bmf = 2048
testObj:BMFFunc()
-- 访问静态成员,点号
cs.MyNamespace.BaseClass.bsf = 4096
4 相关知识点对比
实例访问 VS 静态访问
实例:必须先 new 出对象,用:调用方法; static 静态:直接类名.访问,不用创建对象。
5 模块拓展:结构体 struct 在 Lua 中等价用 table 传参。
三、C# 多返回值函数在 Lua 中调用(ref/out 参数)
1 概念
C# 函数通过ref传入、out输出实现多返回;Lua 调用时,结构体参数直接传 table;ref 需要传入初始值;out 不需要传入初始值。
2 特性 & 规则
-
ref:实参必须传入初始值;函数内可以读取 + 修改;
-
out:不需要传入初始值;函数执行完成向外输出数据;
-
C# 的 struct 结构体,Lua 传参直接传 table;
-
函数多个 out/ref,Lua 接收多个返回值。
3 语法 & 代码片段
-- 调用C#多返回函数,struct用table传参,ref传初始值
local a,b,c,d = testObj:MultiFunc(
{x=3,y="ABC"}, --结构体对应table
100, --ref参数(需要初始值)
nil, --out参数不需要初始输入
function(s) print("Lua回调:",s) end --Action委托回调
)
print(a,b,c,d)
4 相关知识点对比
ref VS out
ref:进入函数可读可改,调用方必须传初始数据; out:只负责向外输出,调用不需要传入有效值。
5 模块拓展:C# 返回委托,Lua 可以接收并调用。
四、重载函数调用坑点(int /float)
1 概念
Lua 内部数字全部为 double (number),调用 C# 重载函数时无法区分 int、float、double;匹配顺序取决于 C# 桥接生成时方法注册顺序,先注册的重载优先被执行。
2 特性 & 规则
-
Lua 只有一种 number,没有区分整数、单精度、双精度;
-
同名重载,如果一个 int 一个 float,传数字时优先匹配靠前注册的那一个;
-
业务规避方案:尽量避免 C# 写仅数值类型区分的重载;或者封装不同名字辅助函数。
3 相关知识点对比
C# 编译期重载匹配 VS xLua 运行时匹配
C# 编译:编译阶段根据实参类型精确匹配; Lua:运行时,全部 number,按桥接注册先后顺序匹配。
5 模块拓展:字符串、布尔、对象类型重载可以正常区分。
五、可变参数 params 数组函数调用
1 概念
C# params可变参数数组,Lua 调用直接依次传入多个实参,xLua 内部自动包装成数组。
2 特性 & 规则
-
C#
params T[]可变数组;Lua 直接写多个参数; -
内部 xLua 自动把多个实参封装为 C# 数组传入。
3 语法 & 代码片段
--C#: void TestParams(int a, params string[] args)
testObj:TestParams(123,"hello","world","test")
4 相关知识点对比
C# params 数组 VS Lua ... 可变参数
C# params:C# 侧定义数组;Lua 直接平铺传参; Lua ...:Lua 脚本原生可变参数。
5 模块拓展:params 支持引用类型对象数组。
六、委托 Delegate、事件 Event Lua 注册 / 移除
1 概念
Lua 中可以构造匿名函数,去订阅 C# 委托、事件;实现 Lua 逻辑订阅 C# 侧的回调。
2 特性 & 规则
-
Lua 没有
+=、-=运算符;委托多播使用= 原委托 + 新委托;移除用= 原委托 待移除委托; -
事件 Event:外部只能
+/-=订阅取消,不能直接赋值;xLua 支持 Lua 匿名函数注册事件; -
多播委托可以挂载多个 Lua 函数,全部会被执行。
3 语法 & 代码片段
--委托多播
testObj.testDelegate = testObj.testDelegate + function(s)
print("Lua委托回调",s)
end
--事件注册
testObj:Add_TestEvent(function()
print("Lua事件触发")
end)
--事件移除
testObj:Remove_TestEvent(function()
print("Lua事件触发")
end)
--C#内部调用触发事件
testObj:CallEvent()
注意:xLua 会自动生成 Add_XXX / Remove_XXX 包装方法供 Lua 访问事件。
4 相关知识点对比
普通委托字段 VS event 事件
委托字段:可以直接覆盖赋值; event 事件:禁止外部直接赋值,只能加 / 减订阅。
5 模块拓展:回调注意对象生命周期,防止委托内存泄漏。
七、xLua 底层交互原理:虚拟栈 + 桥接 Gen 文件
1 概念
Lua 与 C# 并不直接互相调用;中间依靠虚拟栈做数据中转站,配合 Generate Code 生成的桥接(Gen)文件完成跨语言交互。
2 特性 & 规则
-
虚拟栈:
任意一方要传递数据,先压入虚拟栈; 另一方从栈顶读取数据;所有参数、返回值全部经过栈中转; 不是直接内存访问,会带来少量性能开销。
-
Gen 桥接文件:XLua 菜单
Generate Code生成,存放在 Gen 文件夹;
标记
[CSharpCallLua]/[LuaCallCSharp]的类、接口、委托,会生成对应的桥接代码; Lua 不能直接调用 C#;通过桥接代码再去调用原生 C#; 修改 C# 被标记的类 / 委托,必须重新 Generate Code、Inject 注入,否则报错。 -
整体调用链路:
C# 调用 Lua:C# → xLua C++ DLL → 虚拟栈 → Lua 脚本 Lua 调用 C#:Lua → Gen 桥接代码 → 虚拟栈 → C# 业务代码
4 相关知识点对比
无桥接 VS Gen 桥接
没有桥接:Lua 无法识别 C# 自定义类型; Gen 桥接:生成适配层,打通两边类型系统。
5 模块拓展:面试高频考点,热更新笔试常考虚拟栈原理。
综合拓展
1 业务流程 Lua 使用 cs. 前缀访问 Unity/C# → 创建对象、Find 查找、GetComponent 获取组件、读写属性;冒号调用实例方法、点号调用静态;调用 ref/out 多返回函数;注意 number 无法区分 int/float 重载坑;调用 params 可变参数;Lua 匿名函数订阅 C# 委托事件;理解虚拟栈 + Gen 桥接底层交互。
2 高频 Bug 排查清单
-
Lua 访问 C# 类报错:忘记写
cs.命名空间前缀; -
实例方法调用报错:实例方法误用
.,应当使用:冒号; -
重载函数调用结果不符合预期:Lua number 不区分 int/float,受桥接注册顺序影响;
-
调用委托 / 事件报错:C# 类型没有打上标签,没有执行 Generate Code 生成桥接;
-
修改 C# 标记类之后行为异常:修改类型没有重新 Generate Code+Inject 注入。
3 核心考点 cs 命名空间前缀;.与:调用区分;Lua 创建 C# 对象;ref/out 多返回值调用;重载函数 int/float 的坑;params 可变参数;Lua 订阅 C# 委托事件;xLua 虚拟栈原理;Gen 桥接文件作用、Generate Code 时机。
4 进阶拓展学习方向 xLua Hotfix 热补丁;AB 包下载 Lua 脚本 + AddLoader 完整热更新 Demo;内存泄漏排查(委托、LuaEnv 释放)。