如何使用 setmetatable 围绕 C# 对象创建 Lua 包装类



我正在为我目前正在用 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而不是C#编写包装类来实现什么,然后公开该类型,但我注意到了这一点:

对我来说,NativeClass.__new()从来没有像你试图的那样在MoonSharp中工作过

self.__codeElement = BLU_UIElement.__new();

出于这个原因,我为我的本机类创建自定义构造函数,并将它们作为委托传递给全局命名空间(尽管必须注册其类型)。它看起来很像你通常构造一个对象。只是没有新关键字:

在 C# 中

public NativeClass{
public static NativeClass construct()
{
return new NativeClass();
}
}

将静态方法作为委托传递给脚本:

script["NativeClass"] = (Func<NativeClass>)NativeClass.construct;

然后你可以在MoonSharp中创建一个这样的新实例:

x = NativeClass()

编辑:所以没有读到你试图用字符串来做到这一点。也许你应该考虑不要用 LUA 而是用 C# 编写包装类,或者是否有禁止这样做的原因?

我有一个朋友,他对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

最新更新