C# Variant

Подробное описание Variant в целом см. на странице документации Variant.

Godot.Variant используется для представления собственного типа Godot Variant. Любой Variant-compatible type может быть преобразован в него. Мы рекомендуем избегать Godot.Variant, если только это не требуется для взаимодействия с нетипизированными API движка. По возможности используйте преимущества типобезопасности C#.

Преобразование типа C#, совместимого с Variant, в Godot.Variant можно выполнить с помощью неявных преобразований. Существуют также перегрузки метода CreateFrom и универсальные методы Variant.From<T>. Различается только синтаксис, а поведение остаётся прежним.

int x = 42;
Variant numberVariant = x;
Variant helloVariant = "Hello, World!";

Variant numberVariant2 = Variant.CreateFrom(x);
Variant numberVariant3 = Variant.From(x);

Неявные преобразования в Godot.Variant делают передачу вариантов в качестве аргументов метода очень удобной. Например, третий аргумент tween_property, задающий конечный цвет анимации, — это Godot.Variant.

Tween tween = CreateTween();
tween.TweenProperty(GetNode("Sprite"), "modulate", Colors.Red, 1.0f);

Преобразование из Godot.Variant в тип C# можно выполнить с помощью явных преобразований. Существуют также методы Variant.As{TYPE} и универсальный метод Variant.As<T>. Все они ведут себя одинаково.

int number = (int)numberVariant;
string hello = (string)helloVariant;

int number2 = numberVariant.As<int>();
int number3 = numberVariant.AsInt32();

Примечание

Методы Variant.As{TYPE} обычно именуются по типам C# (Int32), а не по ключевым словам C# (int).

Если тип Variant не соответствует целевому типу конверсии, последствия различаются в зависимости от исходных и целевых значений.

  • Преобразование может проверить значение и вернуть похожее, но потенциально неожиданное значение целевого типа. Например, строка "42a" может быть преобразована в целое число 42.

  • Может быть возвращено значение по умолчанию для целевого типа.

  • Может быть возвращен пустой массив.

  • Может быть выдано исключение.

Преобразование в правильный тип позволяет избежать сложного поведения и является предпочтительным.

Свойство Variant.Obj возвращает object C# с правильным значением для любого варианта. Это может быть полезно, когда тип варианта совершенно неизвестен. Однако, если возможно, предпочитайте более точные преобразования. Variant.Obj вычисляет switch для Variant.VariantType, и это может быть необязательно. Кроме того, если результат является типом значения, он упаковывается.

Например, если вероятность того, что Variant.As<MyNode>() выдаст недопустимое исключение приведения типов, неприемлема, рассмотрите возможность использования вместо этого шаблона типа Variant.As<GodotObject>() is MyNode n.

Примечание

Поскольку тип Variant в C# является структурой, он не может быть равен "null". Чтобы создать вариант со значением "null", используйте ключевое слово default или конструктор без параметров Godot.Variant.

Variant-compatible типы

Совместимый с Variant тип может быть преобразован в Godot.Variant и обратно. Следующие типы C# совместимы с Variant:

  • Все built-in value types (встроенные типы значений), кроме decimal, nint и nuint.

  • string.

  • Классы, производные от GodotObject.

  • Типы коллекций, определенные в пространстве имен Godot.Collections.

Полный список типов Variant и их эквивалентных типов C#:

Variant.Type

C# Type

Nil

null (Не тип)

Bool

bool

Int

long (Godot хранит 64-битные целые числа в Variant)

Float

double (Godot хранит 64-битные целые числа в Variant)

String

string

Vector2

Godot.Vector2

Vector2I

Godot.Vector2I

Rect2

Godot.Rect2

Rect2I

Godot.Rect2I

Vector3

Godot.Vector3

Vector3I

Godot.Vector3I

Transform2D

Godot.Transform2D

Vector4

Godot.Vector4

Vector4I

Godot.Vector4I

Plane

Godot.Plane

Quaternion

Godot.Quaternion

Aabb

Godot.Aabb

Basis

Godot.Basis

Transform3D

Godot.Transform3D

Projection

Godot.Projection

Color

Godot.Color

StringName

Godot.StringName

NodePath

Godot.NodePath

Rid

Godot.Rid

Object

Godot.GodotObject или любой производный тип.

Callable

Godot.Callable

Signal

Godot.Signal

Dictionary

Godot.Collections.Dictionary

Массив

Godot.Collections.Array

PackedByteArray

byte[]

PackedInt32Array

int[]

PackedInt64Array

long[]

PackedFloat32Array

float[]

PackedFloat64Array

double[]

PackedStringArray

string[]

PackedVector2Array

Godot.Vector2[]

PackedVector3Array

Godot.Vector3[]

PackedVector4Array

Godot.Vector4[]

PackedColorArray

Godot.Color[]

Предупреждение

Godot использует 64-битные целые числа и числа с плавающей точкой в Variant. Поддерживаются целые и числа с плавающей точкой меньшего размера, такие как int, short и float, поскольку они могут быть представлены в более крупном типе. Имейте в виду, что при преобразовании использование неправильного типа может привести к потенциальной потере точности.

Предупреждение

Перечисления поддерживаются в Godot.Variant, поскольку их базовый тип — целочисленный, и все они совместимы. Однако неявных преобразований не существует: перечислимые типы необходимо вручную преобразовать в базовый целочисленный тип, прежде чем их можно будет преобразовать в Godot.Variant или из него, или использовать универсальные методы Variant.As<T> и Variant.From<T> для их преобразования.

enum MyEnum { A, B, C }

Variant variant1 = (int)MyEnum.A;
MyEnum enum1 = (MyEnum)(int)variant1;

Variant variant2 = Variant.From(MyEnum.A);
MyEnum enum2 = variant2.As<MyEnum>();

Использование варианта в общем контексте

При использовании универсальных типов может возникнуть необходимость ограничить универсальный тип T только одним из типов, совместимых с Variant. Этого можно добиться с помощью атрибута [MustBeVariant].

public void MethodThatOnlySupportsVariants<[MustBeVariant] T>(T onlyVariant)
{
    // Do something with the Variant-compatible value.
}

В сочетании с универсальным методом Variant.From<T> это позволяет получить экземпляр Godot.Variant из экземпляра универсального типа T. Затем его можно использовать в любом API, который поддерживает только структуру Godot.Variant.

public void Method1<[MustBeVariant] T>(T variantCompatible)
{
    Variant variant = Variant.From(variantCompatible);
    Method2(variant);
}

public void Method2(Variant variant)
{
    // Do something with variant.
}

Чтобы вызвать метод с универсальным параметром, аннотированным атрибутом [MustBeVariant], значение должно быть типом, совместимым с Variant, или универсальным типом T, также аннотированным атрибутом [MustBeVariant].

public class ObjectDerivedClass : GodotObject { }

public class NonObjectDerivedClass { }

public void Main<[MustBeVariant] T1, T2>(T1 someGeneric1, T2 someGeneric2)
{
    MyMethod(42); // Works because `int` is a Variant-compatible type.
    MyMethod(new ObjectDerivedClass()); // Works because any type that derives from `GodotObject` is a Variant-compatible type.
    MyMethod(new NonObjectDerivedClass()); // Does NOT work because the type is not Variant-compatible.
    MyMethod(someGeneric1); // Works because `T1` is annotated with the `[MustBeVariant]` attribute.
    MyMethod(someGeneric2); // Does NOT work because `T2` is NOT annotated with the `[MustBeVariant]` attribute.
}

public void MyMethod<[MustBeVariant] T>(T variant)
{
    // Do something with variant.
}