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 相容型別:
所有 內建值型別,除了
decimal、nint與nuint。string。繼承自 GodotObject 的類別。
在
Godot.Collections命名空間定義的集合型別。
Variant 型別與其對應 C# 型別的完整列表:
Variant 型別 |
C# 型別 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
警告
Godot 在 Variant 中使用 64 位元整數與浮點數。較小的整數與浮點型別(例如 int、short、float)因可被容納於較大型別中而受到支援。請注意,執行轉型時若使用錯誤的型別,可能會導致精度損失。
警告
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.
}