为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
繁华开满天机 2022-12-24 10:10:16
我正在为我目前正在使用 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;endBLU_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以了解我做错了什么,但我什么也没想到。我很欣赏这方面的任何指导,我已经研究了几天但没有弄清楚,并且在线搜索通常只会显示与我已经在做的类似的代码。
查看完整描述

2 回答

?
慕婉清6462132

TA贡献1804条经验 获得超2个赞

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


查看完整回答
反对 回复 2022-12-24
?
饮歌长啸

TA贡献1951条经验 获得超3个赞

我必须承认我不完全确定,你试图通过在 LUA 而不是 C# 中编写包装类然后公开该类型来实现什么,但我注意到了这一点:


对我来说,NativeClass .__new() 从来没有在 MoonSharp 中成功过,就像你试图在


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# 中编写,或者是否有禁止这样做的原因?


查看完整回答
反对 回复 2022-12-24
  • 2 回答
  • 0 关注
  • 105 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信