如何使用 setmetatable 来创建 Lua 包装类以包裹一个 C# 对象
我正在用 C# 为我的游戏创建一些 UI,并希望将所有东西暴露给 Lua,以便我的艺术家可以进行小的调整而不需要进行任何代码。我正在使用 MoonSharp 将 Lua 脚本集成到我的项目中。
这是我当前的 UIElement 包装类的情况:
UIElement = {};
UIElement.__index = UIElement;
setmetatable(UIElement, {
__index = function (self, key)
local codeElement = rawget(self, "__codeElement");
local field = codeElement and codeElement[key];
if type(field) == "function" then
return function(obj, ...)
if obj == self then
return field(codeElement, ...);
else
return field(obj, ...)
end
end;
else
return field;
end
end,
__call = function(cls, ...)
return cls.new(...);
end,
});
function UIElement.new()
local self = setmetatable({}, UIElement);
self.__codeElement = BLU_UIElement.__new();
return self;
end
BLU_UIElement 是我的 C# 类,通过 MoonSharp API 暴露给 Lua。当直接使用对象时,它可以正常工作,并具有诸如 SetPos、SetColor 等函数。
UIElement 旨在成为我的 Lua 中的“类”,以包装并扩展我的 C# 对象。
当我在脚本的其他地方实例化 UIElement 并尝试调用函数(例如 SetPos)时,它确实进入了 __index 函数。但是,rawget 调用总是返回 nil。似乎与 BLU_UIElement 无关。我已经尝试了非常简单的事情,例如在构造函数中添加字符串 ID 值,并在 __index 函数中尝试 rawget 它,但它也返回 nil。
我想我可能没有正确地设置类或对象本身的元表,但我不确定问题出在哪里。我一直在这里寻找建议:http://lua-users.org/wiki/ObjectOrientationTutorial,但是没有什么能引起我的注意。
我欢迎任何关于此的指导,我已经看了几天了,也没有找出来,搜索在线通常只显示类似于我已经做过的代码。
我有一个比我更经验丰富的使用Lua元表的朋友来看了一下。为了帮助其他人,我在这里发布答案。
问题在于我试图将UIElement表同时用作“类”表和“对象”元表。在__index函数中调用rawget时,它试图在UIElement表中查找,而不是在UIElement.new()中创建的self表中查找。将这两个拆分为不同的表(一个用于类,一个用于对象元表)可以解决问题。
这是我的代码更新和工作代码:
UIElement = {};
setmetatable( UIElement, {
__call = function( cls, ... )
return cls.new( ... );
end,
} );
UIElement.objectMetaTable = {
__index = function( self, key )
local objectValue = rawget(self, key);
if objectValue ~= nil then
return objectValue;
end
local classValue = UIElement[key];
if classValue ~= nil then
return classValue;
end
local codeElement = rawget(self, "__codeElement");
if codeElement then
return codeElement[key];
end
end,
};
function UIElement.new()
local newInstance = setmetatable( { id = "blah" }, UIElement.objectMetaTable );
newInstance.__codeElement = BLU_UIElement.__new();
return newInstance;
end
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?

我得承认,我不完全确定你试图通过使用 LUA 而不是 C#编写包装器类并公开该类型来实现什么,但我注意到了这一点:
就我而言,在 MoonSharp 中,像你试图在下面这样做的那样,NativeClass.__new() 从未成功:
self.__codeElement = BLU_UIElement.__new();出于这个原因,我为我的本地类创建了自定义构造函数,并将它们作为委托传递给全局名称空间(但它的类型必须被注册)。它看起来很像你通常构造一个对象。只是没有 new 关键字:
在 C#中:
public NativeClass{ public static NativeClass construct() { return new NativeClass(); } }将静态方法作为委托传递到脚本中:
script["NativeClass"] = (Func<NativeClass>)NativeClass.construct;然后你可以在 MoonSharp 中这样创建一个新实例:
x = NativeClass()编辑:因此,我没有读到你尝试使用字符串来实现的情况。也许你应该考虑不在 LUA 中编写包装器类,而是在 C#中编写它,或者有什么原因禁止这样做?