猿问

如何使用 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以了解我做错了什么,但我什么也没想到。


我很欣赏这方面的任何指导,我已经研究了几天但没有弄清楚,并且在线搜索通常只会显示与我已经在做的类似的代码。


繁华开满天机
浏览 106回答 2
2回答

慕婉清6462132

我有一个朋友,他对 Lua 元表的经验比我看的要丰富得多。在这里发布答案以防它帮助其他人。问题是我试图将 UIElement 表用作“类”表和“对象”元表。在 __index 函数内调用 rawget 时,它试图在 UIElement 表中查找内容,而不是在 UIElement.new() 中创建的自身表中查找内容。将这两个拆分成不同的表(一个用于类,一个用于对象元表)固定的东西。这是我更新的工作代码: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 而不是 C# 中编写包装类然后公开该类型来实现什么,但我注意到了这一点:对我来说,NativeClass .__new() 从来没有在 MoonSharp 中成功过,就像你试图在self.__codeElement = BLU_UIElement.__new();出于这个原因,我为我的本地类创建了自定义构造函数,并将它们作为委托传递给全局命名空间(尽管它的类型必须注册)。它看起来很像您通常会构造一个对象。只是没有 new 关键字:在 C# 中public NativeClass{&nbsp; &nbsp;public static NativeClass construct()&nbsp; &nbsp;{&nbsp; &nbsp; &nbsp; return new NativeClass();&nbsp; &nbsp;}}将静态方法作为委托传递给脚本:script["NativeClass"] = (Func<NativeClass>)NativeClass.construct;然后你可以在 MoonSharp 中创建一个像这样的新实例:x = NativeClass()编辑:所以没有读到你试图用字符串来做到这一点。也许您应该考虑不在 LUA 中编写包装类,而在 C# 中编写,或者是否有禁止这样做的原因?
随时随地看视频慕课网APP

相关分类

Go
我要回答