如何使用 setmetatable 在 C# 对象周围创建 Lua 包装器 class
How to use setmetatable to create a Lua wrapper class around a C# object
我正在为我目前正在使用 C# 开发的游戏创建一些 UI,并希望将所有内容公开到 Lua,以便我的美工人员可以进行小的调整,而无需在代码中做任何事情。我正在使用 MoonSharp 将 Lua 脚本集成到我的项目中。
这是我目前的 UIElement 包装器 class:
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# class,它通过 MoonSharp API 暴露给 Lua。直接操作对象时可以正常工作,具有SetPos、SetColor等功能
UIElement 旨在成为我在 Lua 中的 "class" 以包装和扩展我的 C# 对象。
当我在脚本的其他地方实例化一个 UIElement 并尝试调用一个函数(例如 SetPos)时,它确实正确地进入了 __index 函数。但是,rawget 调用总是 returns nil。它似乎也不是特定于 BLU_UIElement 的。我已经尝试了一些非常简单的事情,比如在构造函数中添加一个字符串 ID 值并尝试在 __index 函数中对其进行 rawget,但它也是 returns nil.
我假设我只是在 class 或对象本身上错误地设置了亚稳态,但我不确定问题出在哪里。我一直在此处查看:http://lua-users.org/wiki/ObjectOrientationTutorial 想知道我做错了什么,但我什么也没想到。
我很感激任何关于这方面的指导,我已经研究了几天都没有搞清楚,在线搜索通常只会显示与我已经在做的类似的代码。
我不得不承认我不完全确定,你试图通过在 LUA 而不是 C# 中编写你的包装器 class 来实现什么,然后公开该类型,但我注意到了这一点:
对我来说 NativeClass.__new() 从来没有像您在
尝试那样在 MoonSharp 中成功
self.__codeElement = BLU_UIElement.__new();
出于这个原因,我为我的原生 classes 创建了自定义 constructor-functions,并将它们作为委托传递给全局命名空间(尽管它的类型必须注册)。它看起来很像您通常会构造一个对象。只是没有新关键字:
在 C# 中
public NativeClass{
public static NativeClass construct()
{
return new NativeClass();
}
}
将静态方法作为委托传递给脚本:
script["NativeClass"] = (Func<NativeClass>)NativeClass.construct;
然后您可以在 MoonSharp 中像这样创建一个新实例:
x = NativeClass()
编辑:所以没有读到您曾尝试使用字符串执行此操作。也许您应该考虑不在 LUA 中编写包装器 class,而是在 C# 中,或者是否有禁止这样做的原因?
我有一个朋友在 Lua metatables 方面比我更有经验。在这里发布答案以防对其他人有帮助。
问题是我试图将 UIElement table 用作 "class" table 以及 "object" 元 table。在 __index 函数内调用 rawget 时,它试图在 UIElement table 中查找内容,而不是在 UIElement.new() 中创建的自身 table。将这两个拆分成不同的 tables(一个用于 class,一个用于对象元 table)固定的东西。
这是我更新后的工作代码:
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
我正在为我目前正在使用 C# 开发的游戏创建一些 UI,并希望将所有内容公开到 Lua,以便我的美工人员可以进行小的调整,而无需在代码中做任何事情。我正在使用 MoonSharp 将 Lua 脚本集成到我的项目中。
这是我目前的 UIElement 包装器 class:
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# class,它通过 MoonSharp API 暴露给 Lua。直接操作对象时可以正常工作,具有SetPos、SetColor等功能
UIElement 旨在成为我在 Lua 中的 "class" 以包装和扩展我的 C# 对象。
当我在脚本的其他地方实例化一个 UIElement 并尝试调用一个函数(例如 SetPos)时,它确实正确地进入了 __index 函数。但是,rawget 调用总是 returns nil。它似乎也不是特定于 BLU_UIElement 的。我已经尝试了一些非常简单的事情,比如在构造函数中添加一个字符串 ID 值并尝试在 __index 函数中对其进行 rawget,但它也是 returns nil.
我假设我只是在 class 或对象本身上错误地设置了亚稳态,但我不确定问题出在哪里。我一直在此处查看:http://lua-users.org/wiki/ObjectOrientationTutorial 想知道我做错了什么,但我什么也没想到。
我很感激任何关于这方面的指导,我已经研究了几天都没有搞清楚,在线搜索通常只会显示与我已经在做的类似的代码。
我不得不承认我不完全确定,你试图通过在 LUA 而不是 C# 中编写你的包装器 class 来实现什么,然后公开该类型,但我注意到了这一点:
对我来说 NativeClass.__new() 从来没有像您在
尝试那样在 MoonSharp 中成功self.__codeElement = BLU_UIElement.__new();
出于这个原因,我为我的原生 classes 创建了自定义 constructor-functions,并将它们作为委托传递给全局命名空间(尽管它的类型必须注册)。它看起来很像您通常会构造一个对象。只是没有新关键字:
在 C# 中
public NativeClass{
public static NativeClass construct()
{
return new NativeClass();
}
}
将静态方法作为委托传递给脚本:
script["NativeClass"] = (Func<NativeClass>)NativeClass.construct;
然后您可以在 MoonSharp 中像这样创建一个新实例:
x = NativeClass()
编辑:所以没有读到您曾尝试使用字符串执行此操作。也许您应该考虑不在 LUA 中编写包装器 class,而是在 C# 中,或者是否有禁止这样做的原因?
我有一个朋友在 Lua metatables 方面比我更有经验。在这里发布答案以防对其他人有帮助。
问题是我试图将 UIElement table 用作 "class" table 以及 "object" 元 table。在 __index 函数内调用 rawget 时,它试图在 UIElement table 中查找内容,而不是在 UIElement.new() 中创建的自身 table。将这两个拆分成不同的 tables(一个用于 class,一个用于对象元 table)固定的东西。
这是我更新后的工作代码:
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