Как использовать setmetatable для создания класса-оболочки Lua вокруг объекта C #

#c# #lua #moonsharp

#c# #lua #moonsharp

Вопрос:

Я создаю некоторый пользовательский интерфейс для игры, над которой я сейчас работаю на C #, и хочу предоставить все вплоть до 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 #, который доступен для Lua через MoonSharp API. Он работает должным образом при работе непосредственно с объектом и имеет такие функции, как SetPos, setColor и т.д.

UIElement предназначен для того, чтобы быть моим «классом» в Lua для переноса и расширения моего объекта C #.

Когда я создаю экземпляр UIElement в другом месте скрипта и пытаюсь вызвать функцию (например, SetPos ), она правильно попадает в функцию __index . Однако вызов rawget всегда возвращает nil . Это также не похоже на BLU_UIElement . Я уже пробовал что-то очень простое, например, добавить значение string ID в конструктор и попытаться получить его в rawget в функции __index , но он также возвращает nil .

Я предполагаю, что я просто делаю что-то неправильно, настраивая метастабилизатор либо для класса, либо для самого объекта, но я не совсем уверен, в чем проблема. Я искал здесь: http://lua-users.org/wiki/ObjectOrientationTutorial чтобы получить представление о том, что я делаю не так, но мне ничего не приходит в голову.

Я ценю любые рекомендации по этому поводу, я смотрел на это пару дней, не разбираясь в этом, и поиск в Интернете, как правило, просто показывает код, аналогичный тому, что я уже делаю.

Ответ №1:

Я должен признать, что я не совсем уверен, чего вы пытаетесь достичь, написав свой класс-оболочку на 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 #, или есть причина, которая запрещает это?

Комментарии:

1. Я хотел выполнить основную часть работы в Lua по двум причинам. Большая проблема заключается в том, что это делает систему пользовательского интерфейса немного более модульной, поэтому, если мы меняем движки или языки, единственное, что нужно изменить, это один базовый класс, определенный в C #, в то время как все остальные вещи, определенные в Lua, остаются неизменными. Вторая причина заключается в том, что я работаю с некоторыми некодерами в моей команде. Они открыты для редактирования файлов Lua и создания новых классов или функций в соответствии со своими потребностями. Однако они нервничают, когда кто-то просит их коснуться кода.

Ответ №2:

У меня был друг, у которого гораздо больше опыта работы с метатаблицами Lua, чем у меня, взгляните. Публикую ответ здесь на случай, если он поможет кому-либо еще.

Проблема заключалась в том, что я пытался использовать таблицу UIElement как в качестве таблицы «class», так и в качестве метатаблицы «object». При вызове rawget внутри функции __index он пытался найти что-то в таблице UIElement вместо собственной таблицы, созданной в UIElement.new() . Разделение этих двух таблиц на отдельные таблицы (одна для класса, одна для объекта metatable) исправило ситуацию.

Вот мой обновленный и рабочий код:

 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