Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

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。當 Variant 型別完全未知時這會很有用。不過,建議仍盡量使用更具體的轉換。Variant.Obj 會對 Variant.VariantType 做 switch 判斷,這可能並非必要。此外,如果結果是值型別,則會發生 boxing。

舉例來說,如果你不能接受 Variant.As<MyNode>() 可能丟出無效轉型例外,可以改用 Variant.As<GodotObject>() is MyNode n 這種型別模式。

備註

由於 C# 中的 Variant 型別是 struct,無法為 null。若要建立「null」的 Variant,請使用 default 關鍵字或 Godot.Variant 的無參數建構式。

Variant 相容型別

Variant 相容型別可以與 Godot.Variant 互相轉換。以下 C# 型別皆為 Variant 相容型別:

  • 所有 內建值型別,除了 decimalnintnuint

  • string

  • 繼承自 GodotObject 的類別。

  • Godot.Collections 命名空間定義的集合型別。

Variant 型別與其對應 C# 型別的完整列表:

Variant 型別

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 支援 enum,因為 enum 的基礎型別為相容的整數型別。不過,enum 並無隱式轉換,必須手動轉為其底層整數型別後,才能轉換為 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

使用泛型時,你可以透過 [MustBeVariant] 屬性,限制泛型 T 僅能為 Variant 相容型別之一。

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