C# Variant

对于 Variant 的详细解释,请参阅 Variant 文档页面。

Godot.Variant 用于表示 Godot 的原生 Variant 类型。任何 Variant 兼容类型 都可以和它进行转换。我们建议仅在与无类型的引擎 API 交互时使用 Godot.Variant。尽可能利用 C# 的类型安全性。

将 Variant 兼容的 C# 类型转换为 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 属性返回一个 C# object,其中包含任何变体的正确值。当变体的类型完全未知时,这可能很有用。但是,如果可能,最好使用更具体的转换。Variant.Obj 会关于 Variant.VariantType 执行一个 switch,这可能不是必需的。此外,如果结果是值类型,则会对其进行装箱。

例如,如果 Variant.As<MyNode>() 引发一个无效转换异常的可能性是不可接受的,请考虑改用 Variant.As<GodotObject>() is MyNode n 类型模式。

备注

由于 C# 中的 Variant 类型是一个结构体,它不能为 null。要创建一个 “null” Variant,请使用 default 关键字或 Godot.Variant 无参数构造函数。

Variant 兼容类型

Variant 兼容类型可以与 Godot.Variant 相互转换。以下 C# 类型与 Variant 兼容:

  • 除了 decimalnintnuint 之外,所有的 内置值类型

  • String

  • GodotObject 派生的类。

  • Godot.Collections 命名空间中定义的集合类型。

Variant 类型的完整列表及其对应的 C# 类型:

Variant.Type

C# 类型

Nil

null (不是类型)

Bool

bool

Int

long (Godot 在 Variant 中存储 64 位整数)

Float

double (Godot 在 Variant 中存储 64 位浮点数)

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

Array

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 在 Variant 中使用 64 位的整数和浮点数。较小的整数和浮点数类型,如 intshortfloat,也是支持的,因为它们可以容纳在更大的类型中。请注意,执行转换时,使用错误的类型可能会导致潜在的精度损失。

警告

枚举类型由于其底层类型是整数类型,因此都与 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>();

在泛型上下文中使用 Variant

在使用泛型时,你可能希望限制泛型 T 类型仅为 Variant 兼容类型之一。这可以通过使用 [MustBeVariant] 特性来实现。

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

结合泛型 Variant.From<T> 可以让你从一个泛型 T 类型的实例中获取一个 Godot.Variant 的实例。然后它可以用在任何只支持 Godot.Variant 结构体的 API 中。

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 兼容类型或者带有 [MustBeVariant] 特性标注的泛型 T 类型。

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.
}