reckfellENGINE

Variant: типы, проверка данных и общие контейнеры

Строгое чтение данных C#, числовые границы, Nil, копирование и время жизни.

На этой странице

Variant хранит одно значение движка вместе с меткой его типа. Он нужен на динамических границах API: в свойствах, вызовах методов, сигналах и коллекциях движка. Это не замена каждой переменной C#, не контейнер для произвольного CLR-объекта и не формат файла сохранения.

Обычные поля игровой логики оставляйте типизированными. Получив Variant из API или контейнера данных, сначала проверьте тип и ограничения значения, затем преобразуйте его.

Учитывайте хранимый тип

Значение C#Метка движкаКак читать
default(Variant), null вместо объекта движкаNilObj возвращает null. Пустая строка и пустая коллекция — другие значения.
boolBoolAsBool. Не принимайте его незаметно вместо целочисленного поля.
int, longIntХранится знаковое 64-битное целое; Obj упаковывает его как long.
float, doubleFloatХранится число двойной точности; Obj упаковывает его как double. Расширение не восстанавливает точность исходного float.
stringStringAsString. Это текст, а не автоматически проверенное число для вашей схемы.
Vector2 и другие поддерживаемые типы значений движкаСоответствующая меткаЧитайте подходящий тип; у Vector2I и Vector2 разные метки.
Экземпляр наследника ReckfellObjectObjectИдентичность объекта, а не его клон или гарантия вечного существования.
Reckfell.Collections.Array / DictionaryArray / DictionaryИзвлечение сохраняет общий контейнер.
int[]PackedInt32ArrayПреобразование копирует содержимое управляемого массива; AsInt32Array возвращает управляемую копию.

Проверяйте хранимую метку движка через VariantType. Выражение value.Obj is int не подходит для проверки Variant Int: Obj возвращает long. Аналогично Variant из float даёт упакованный double.

Нативный Variant C++ и оболочка C# работают с одними категориями значений движка, но отличаются представлением в памяти и управлением временем жизни. Размер нативной структуры не описывает стоимость выделений .NET. List<T> или произвольный класс C# не становятся автоматически Array движка или допустимым содержимым Variant; сначала создайте поддерживаемое значение. Обобщённые From<T>/As<T> также требуют поддерживаемого типа.

Преобразование не заменяет проверку

AsInt32, явное приведение к int и As<int>() выполняют преобразование. Они не гарантируют, что исходная метка была Int и что значение помещалось в целевой тип. В установленном движке "42" преобразуется в 42, true — в 1, а 3.75 — в целое 3. Int со значением 2147483648 сужается через AsInt32 до -2147483648.

Если поле должно содержать именно 32-битное целое, сначала проверьте метку и диапазон 64-битного значения. Для позиции определите, допустимы ли неконечные компоненты. Этот помощник отклоняет NaN/бесконечность и требует именно Vector2:

C#
using Reckfell;

public static class VariantBoundary
{
    public static bool TryGetInt32(Variant value, out int result)
    {
        result = 0;
        if (value.VariantType != Variant.Type.Int)
            return false;
        long number = value.AsInt64();
        if (number < int.MinValue || number > int.MaxValue)
            return false;
        result = (int)number;
        return true;
    }

    public static bool TryGetFiniteVector2(Variant value, out Vector2 result)
    {
        result = Vector2.Zero;
        if (value.VariantType != Variant.Type.Vector2)
            return false;
        Vector2 vector = value.AsVector2();
        if (!vector.IsFinite())
            return false;
        result = vector;
        return true;
    }
}

Сохраните его как VariantBoundary.cs. Вызовите VariantBoundary.TryGetInt32(value, out int count) для целочисленного значения или VariantBoundary.TryGetFiniteVector2(value, out Vector2 position) для конечной позиции. False означает несоответствие этому контракту; выходное значение равно нулю. Затем добавьте ограничения предметной области: например, неотрицательное количество или положение внутри уровня.

Эта политика намеренно отклоняет числовую строку, Float без дробной части и Vector2I. Если ваш формат разрешает такие преобразования, реализуйте и опишите отдельные правила вместо случайного принятия всех преобразований движка.

Отличайте отсутствующий ключ от Nil

Используйте Dictionary.TryGetValue, если отсутствие ключа имеет значение. False означает, что ключа нет. True с VariantType Nil означает, что ключ есть и явно содержит Nil. Проверьте оба результата до подстановки значения по умолчанию.

Индексатор Dictionary подходит для заведомо существующего ключа; это не универсальная проверка наличия. Определите, означает ли отсутствие значения настройку по умолчанию, ошибочные данные или другую версию схемы. Не сводите все три случая к нулю.

Различайте копию и общий контейнер

Извлечение Array или Dictionary из Variant создаёт ещё одну оболочку того же контейнера движка. Изменения видны через другие ссылки. Присваивание оболочки другой переменной C# не создаёт независимое содержимое.

Array.Duplicate(false) создаёт новый внешний массив, сохраняя общими вложенные массивы и словари. Duplicate(true) отделяет вложенные контейнеры, но объекты движка остаются ссылками: Entities и игровой мир не клонируются. Для создания объектов применяйте подходящее API инстанцирования или дублирования объектов/ресурсов.

Чтение элемента Array копирует нативное значение Variant. Последующая замена целочисленного элемента не переписывает ранее прочитанное целое. Если прочитанное значение содержит контейнер, его содержимое по-прежнему может быть общим. Копирование оболочки значения и копирование содержимого по ссылке — разные операции.

У управляемых упакованных массивов другое поведение: проверенное преобразование int[] и его извлечение копируют содержимое. Изменение исходного или полученного int[] не редактирует упакованное значение, уже находящееся в Variant. Если нужны изменения, явно назначьте обновлённые данные.

Соблюдайте владение и время жизни объектов

Variant Object сохраняет идентичность объекта. Entity можно явно освободить, даже если на него ссылается Variant. Перед использованием потенциально устаревшего объекта проверяйте IsInstanceValid: метка, отличная от Nil, не доказывает, что объект жив. У RefCounted используется подсчёт ссылок, отличающийся от явного времени жизни Entity и управления деревом.

Оболочка C# Variant реализует IDisposable. Для собственного временного значения, например результата чтения элемента коллекции, using позволяет своевременно освободить нативные данные. Не освобождайте заимствованные значения вызывающего кода: обычное присваивание структуры C# может сохранять общее управление освобождением и не создаёт второго независимого владельца. Не обращайтесь к копиям после освобождения общих данных.

Выполненный пример проверяет метки, числовые преобразования и границы, конечность Vector2, копии управляемых упакованных массивов, общие контейнеры, вложенное дублирование, отсутствующие/Nil-значения и время жизни Entity. Все перегрузки преобразований, произвольные неверные нативные приведения, сериализация и конкурентное изменение отдельно не проверены. Доступные операции перечислены в API Variant; формат сериализации выбирайте отдельно.

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.