型別測試運算子及 Cast 運算式 - is
、as
、typeof
和轉換
這些運算子和運算式會執行型別檢查或型別轉換。 is
運算子會檢查運算式的執行階段型別是否與給定型別相容。 as
運算子會將運算式明確地轉換成給定的型別 (如果其執行階段型別與該型別相容)。 轉換運算式會執行對目標型別的明確轉換。 typeof
運算子會取得某個型別的 System.Type 執行個體。
is 運算子
is
運算子會檢查運算式結果的執行階段型別是否與給定型別相容。 is
運算子也會對將運算式結果對模式進行測試。
使用型別測試 is
運算子運算式有下列格式
E is T
其中 E
是會傳回值的運算式,而 T
是型別名稱或型別參數。 E
不能是匿名方法或 Lambda 運算式。
當運算式結果為非 Null 且下列任何條件成立時,is
運算子會傳回 true
:
運算式結果的執行階段型別為
T
。運算式結果的執行階段型別衍生自型別
T
、實作介面T
,或另一個隱含參考轉換從它到T
。運算式結果的執行階段型別是具有基礎型別
T
的可為 Null 實值型,且Nullable<T>.HasValue 為true
。
is
運算子不會考慮使用者定義轉換。
下列範例示範當運算式結果的執行階段型別衍生自給定型別 (表示型別之間存在參考轉換) 時,is
運算子傳回 true
:
public class Base { }
public class Derived : Base { }
public static class IsOperatorExample
{
public static void Main()
{
object b = new Base();
Console.WriteLine(b is Base); // output: True
Console.WriteLine(b is Derived); // output: False
object d = new Derived();
Console.WriteLine(d is Base); // output: True
Console.WriteLine(d is Derived); // output: True
}
}
下一個範例顯示 is
運算子考慮 Boxing 和 Unboxing 轉換,但不考慮數值轉換:
int i = 27;
Console.WriteLine(i is System.IFormattable); // output: True
object iBoxed = i;
Console.WriteLine(iBoxed is int); // output: True
Console.WriteLine(iBoxed is long); // output: False
包含模式比對的型別測試
is
運算子也會對將運算式結果對模式進行測試。 下列範例示範如何使用宣告模式來檢查運算式的執行階段型別:
int i = 23;
object iBoxed = i;
int? jNullable = 7;
if (iBoxed is int a && jNullable is int b)
{
Console.WriteLine(a + b); // output 30
}
如需支援模式的相關資訊,請參閱模式。
as 運算子
as
運算子將運算式的結果明確地轉換成給定參考或可為 Null 的實值型別。 如果無法轉換,則 as
運算子會傳回 null
。 不同於轉換運算式,as
運算子一律不會擲回例外狀況。
以下格式的運算式
E as T
其中 E
是會傳回值的運算式,而 T
是型別名稱或型別參數,產生的結果與下列相同
E is T ? (T)(E) : (T)null
但只會評估 E
一次。
as
運算子只考慮參考、可為 Null、Boxing 和 Unboxing 轉換。 您無法使用 as
運算子來執行使用者定義轉換。 若要這樣做,請使用轉換運算式。
下列範例示範 as
運算子的用法:
IEnumerable<int> numbers = new List<int>(){10, 20, 30};
IList<int> indexable = numbers as IList<int>;
if (indexable != null)
{
Console.WriteLine(indexable[0] + indexable[indexable.Count - 1]); // output: 40
}
注意
如上述範例所示,您需要將 as
陳述式的結果與 null
比較,以檢查轉換是否成功。 您可以使用 is 運算子測試轉換是否成功,如果成功,便將其結果指派至新變數。
轉換運算式
格式為 (T)E
的轉換運算式會執行明確轉換,將運算式 E
的結果轉換成型別 T
。 如果沒有從型別 E
轉換成型別 T
的明確轉換存在,就會發生編譯時期錯誤。 在執行階段,明確轉換可能不會成功,且轉換運算式可能會擲回例外狀況。
下列範例示範明確的數值和參考轉換:
double x = 1234.7;
int a = (int)x;
Console.WriteLine(a); // output: 1234
int[] ints = [10, 20, 30];
IEnumerable<int> numbers = ints;
IList<int> list = (IList<int>)numbers;
Console.WriteLine(list.Count); // output: 3
Console.WriteLine(list[1]); // output: 20
如需支援之明確轉換的資訊,請參閱 C# 語言規格的明確轉換一節。 如需如何定義自訂明確或隱含型別轉換的資訊,請參閱使用者定義轉換運算子。
() 的其他用法
您也使用括號來呼叫方法或叫用委派。
括弧的其他用法是調整評估運算式中作業的順序。 如需詳細資訊,請參閱 C# 運算子。
typeof 運算子
typeof
運算子會取得型別的 System.Type 執行個體。 typeof
運算子的引數必須是型別名稱或型別參數,如下列範例所示:
void PrintType<T>() => Console.WriteLine(typeof(T));
Console.WriteLine(typeof(List<string>));
PrintType<int>();
PrintType<System.Int32>();
PrintType<Dictionary<int, char>>();
// Output:
// System.Collections.Generic.List`1[System.String]
// System.Int32
// System.Int32
// System.Collections.Generic.Dictionary`2[System.Int32,System.Char]
引數不得為需要中繼資料批註的型別。 範例包含下列型別:
dynamic
string?
(或任何可為 Null 的參考型別)
這些型別不會直接以中繼資料表示。 這些型別包含描述基礎型別的屬性。 在這兩種情況下,您可以使用基礎型別。 您可以使用 object
,而不是dynamic
。 您可以使用 string
,而不是string?
。
您也能搭配使用 typeof
運算子和未繫結的泛型型別。 未繫結泛型型別的名稱必須包含適當數目的逗號,也就是比型別參數數目少一。 下列範例顯示搭配使用 typeof
運算子和未繫結泛型型別的用法:
Console.WriteLine(typeof(Dictionary<,>));
// Output:
// System.Collections.Generic.Dictionary`2[TKey,TValue]
運算式不能作為 typeof
運算子的引數。 若要取得運算式結果執行階段型別的 System.Type 執行個體,請使用 Object.GetType 方法。
使用 typeof
運算子的型別測試
使用 typeof
運算子來檢查運算式結果的執行階段型別,是否完全符合給定型別。 下列範例示範使用 typeof
運算子和 is 運算子,進行型別檢查之間的差異:
public class Animal { }
public class Giraffe : Animal { }
public static class TypeOfExample
{
public static void Main()
{
object b = new Giraffe();
Console.WriteLine(b is Animal); // output: True
Console.WriteLine(b.GetType() == typeof(Animal)); // output: False
Console.WriteLine(b is Giraffe); // output: True
Console.WriteLine(b.GetType() == typeof(Giraffe)); // output: True
}
}
運算子是否可多載
is
、as
和 typeof
運算子無法多載。
使用者定義型別不可多載 ()
運算子,但可定義可由轉換運算式進行的自訂型別轉換。 如需詳細資訊,請參閱使用者定義轉換運算子。
C# 語言規格
如需詳細資訊,請參閱 C# 語言規格的下列幾節: