Наследование классов и реестр ClassDB
Цепочки текущей сборки, создание объектов и отличие класса от родителя в дереве.
Наследование отвечает на вопрос «что это за объект?». Родитель Entity — «где этот экземпляр в дереве?». Тип C#-скрипта отвечает на другой вопрос. Разделяйте их при выборе базового класса, проверке объекта и разработке инструментов редактора.
Основные нативные ветви
| Нативная ветвь | Назначение |
|---|---|
| Object | Отражение, свойства, сигналы и идентичность; оболочка C# — ReckfellObject. |
| Object → RefCounted → Resource | Данные/ресурсы с подсчётом ссылок; автоматически в дерево Entity не входят. |
| Object → Entity | Участие в дереве и жизненный цикл; само по себе не задаёт трансформацию рендеринга. |
| Entity → CanvasItem → Entity2D | Трансформация 2D и иерархия canvas. |
| Entity → CanvasItem → Control | Ветка интерфейса/раскладки; Control не наследует Entity2D. |
| Entity → Entity3D | Ветка трансформации 3D. |
Проверенная полная цепочка Entity2D: Entity2D → CanvasItem → Entity → Object. Его экземпляр может быть дочерним объектом Entity с C#-скриптом, но родительским классом останется CanvasItem. Изменение GetParent() не меняет наследование.
Нативные имена — имена ClassDB, не обязательно имена оболочек C#. Корень называется Object, оболочка — ReckfellObject. GetClass сообщает нативный тип, GetType — управляемый тип CLR. Подключение скрипта не регистрирует автоматически его класс C# как нативный тип ClassDB.
Запросите текущую сборку
Не полагайтесь на старый статический архив дерева классов. Набор зависит от конфигурации сборки, платформы и загруженных расширений. Этот законченный помощник опрашивает работающий реестр:
using System;
using System.Collections.Generic;
using Reckfell;
public static class ObjectRegistry
{
public static string[] InheritanceChain(StringName type)
{
if (!ClassDB.ClassExists(type))
throw new ArgumentException("Unknown native class.", nameof(type));
var result = new List<string>();
string current = type.ToString();
while (current.Length != 0)
{
result.Add(current);
current = ClassDB.GetParentClass(current).ToString();
}
return result.ToArray();
}
public static string[] Descendants(StringName type, bool directOnly = false)
{
if (!ClassDB.ClassExists(type))
throw new ArgumentException("Unknown native class.", nameof(type));
var result = new List<string>();
foreach (string candidate in ClassDB.GetInheritersFromClass(type))
if (!directOnly || ClassDB.GetParentClass(candidate).ToString() == type.ToString())
result.Add(candidate);
result.Sort(StringComparer.Ordinal);
return result.ToArray();
}
public static ReckfellObject CreateNative(StringName type)
{
if (!ClassDB.ClassExists(type))
throw new ArgumentException("Unknown native class.", nameof(type));
if (!ClassDB.CanInstantiate(type))
throw new InvalidOperationException("Class is not instantiable in this context.");
using Variant value = ClassDB.Instantiate(type);
return value.AsReckfellObject()
?? throw new InvalidOperationException("Native creation failed.");
}
}Сохраните как ObjectRegistry.cs. ObjectRegistry.InheritanceChain("Entity2D") возвращает нативную цепочку. ObjectRegistry.Descendants("Entity", true) выбирает прямых потомков, false — также косвенных. Помощник сам сортирует результат ordinal-сравнением. GetInheritersFromClass возвращает всех наследников без запрошенной базы, а не один уровень.
У IsParentClass легко перепутать аргументы: ClassDB.IsParentClass("Entity2D", "Entity") проверяет, является ли Entity базой Entity2D. Эта реализация также возвращает true при одинаковых классах с обеих сторон. GetParentClass возвращает ближайшую нативную базу; у Object имя родителя пустое.
Наличие не разрешает создание
ClassExists проверяет регистрацию, IsClassExposed — публичность, IsClassEnabled — включённость, CanInstantiate — доступность создателя/контекста. Это разные проверки. CanvasItem существует, но в проверенной сборке абстрактен и не создаётся. У редакторских типов и расширений возможны дополнительные требования контекста.
Для обычной игры предпочитайте известный типизированный конструктор. CreateNative нужен инструментам с намеренным выбором нативного класса. Он отбрасывает неизвестные/несоздаваемые имена до Instantiate. Он не создаёт произвольный класс CLR, не подключает C#-скрипт и не возвращает готовый заполненный префаб.
За время жизни возвращённого объекта отвечает вызывающая сторона. Освободите созданный Entity/Object по ситуации либо включите Entity в нужный жизненный цикл дерева. Собственные оболочки RefCounted освобождайте/отпускайте с учётом подсчёта ссылок. Временный Variant помощника освобождается; проверка подтверждает валидность возвращённой оболочки RefCounted после этого.
Проверьте унаследованный API
ClassGetMethodList, ClassGetPropertyList и ClassGetSignalList описывают зарегистрированные метаданные. Для объявлений только текущего класса используйте noInheritance; не выводите наследование из родителя в дереве Entity. У проверенного Entity2D список методов включает get_instance_id по умолчанию и исключает его при noInheritance=true. Свойство position связано с get_position/set_position. Нулевой ClassGetMethodArgumentCount не доказывает наличие метода без аргументов: эта версия возвращает ноль и при отсутствии подходящего привязанного метода.
Имена нативного API чувствительны к регистру. Имя оболочки C# SetPosition не является нативным строковым именем set_position. Для свойств скрипта конкретного экземпляра и динамических пользовательских сигналов опрашивайте сам объект; ClassDB не обязан содержать каждое управляемое/динамическое объявление.
Выбирайте базу по нужной возможности: время жизни данных, дерево, трансформация 2D, раскладка интерфейса или трансформация 3D. Имя класса не превращает дерево в ECS: здесь используется объектное наследование. Привязки и владение разобраны в архитектуре Object.
Помощник и различия реестра/экземпляра проверены в установленном Windows runtime. Статья не обещает один фиксированный полный набор классов для всех экспортов, перезагрузок расширений и настроек редактора.