因為物件具有多型的特性,所以基類型別的變數可以存取衍生類型。 若要存取衍生型別的實例成員,必須將值 轉換 回衍生型別。 不過,類型轉換會帶來拋出InvalidCastException異常的風險。 C# 提供 模式匹配 語句,只有在轉換成功時才會有條件地執行轉換。 C# 也提供 is 和 as 運算子,以測試值是否為特定類型。
下列範例示範如何使用模式比對 is
語句:
var g = new Giraffe();
var a = new Animal();
FeedMammals(g);
FeedMammals(a);
// Output:
// Eating.
// Animal is not a Mammal
SuperNova sn = new SuperNova();
TestForMammals(g);
TestForMammals(sn);
// Output:
// I am an animal.
// SuperNova is not a Mammal
static void FeedMammals(Animal a)
{
if (a is Mammal m)
{
m.Eat();
}
else
{
// variable 'm' is not in scope here, and can't be used.
Console.WriteLine($"{a.GetType().Name} is not a Mammal");
}
}
static void TestForMammals(object o)
{
// You also can use the as operator and test for null
// before referencing the variable.
var m = o as Mammal;
if (m != null)
{
Console.WriteLine(m.ToString());
}
else
{
Console.WriteLine($"{o.GetType().Name} is not a Mammal");
}
}
class Animal
{
public void Eat() { Console.WriteLine("Eating."); }
public override string ToString()
{
return "I am an animal.";
}
}
class Mammal : Animal { }
class Giraffe : Mammal { }
class SuperNova { }
上述範例示範模式比對語法的一些功能。 語句 if (a is Mammal m)
會結合測試與初始化指派。 只有在測試成功時,才會發生指派。 變數 m
只位於已指派的內嵌 if
語句中。 您稍後無法在相同方法中存取 m
。 上述範例也會示範如何使用 as
運算符 ,將對象轉換成指定的型別。
您也可以使用相同的語法來測試 可為 Null 的實值類型 是否有值,如下列範例所示:
int i = 5;
PatternMatchingNullable(i);
int? j = null;
PatternMatchingNullable(j);
double d = 9.78654;
PatternMatchingNullable(d);
PatternMatchingSwitch(i);
PatternMatchingSwitch(j);
PatternMatchingSwitch(d);
static void PatternMatchingNullable(ValueType? val)
{
if (val is int j) // Nullable types are not allowed in patterns
{
Console.WriteLine(j);
}
else if (val is null) // If val is a nullable type with no value, this expression is true
{
Console.WriteLine("val is a nullable type with the null value");
}
else
{
Console.WriteLine("Could not convert " + val.ToString());
}
}
static void PatternMatchingSwitch(ValueType? val)
{
switch (val)
{
case int number:
Console.WriteLine(number);
break;
case long number:
Console.WriteLine(number);
break;
case decimal number:
Console.WriteLine(number);
break;
case float number:
Console.WriteLine(number);
break;
case double number:
Console.WriteLine(number);
break;
case null:
Console.WriteLine("val is a nullable type with the null value");
break;
default:
Console.WriteLine("Could not convert " + val.ToString());
break;
}
}
上述範例示範模式比對的其他功能,以搭配轉換使用。 您可以透過特別檢查變數是否等於null
值,來測試是否符合 Null 模式。 當變數的執行時間值是 null
時, is
檢查型別的語句一律會傳 false
回 。 模式比對 is
語句不允許可為 Null 的值型別,例如 int?
或 Nullable<int>
,但您可以測試任何其他值型別。
is
上述範例中的模式不限於可為 Null 的實值型別。 您也可以使用這些模式來測試參考型別的變數是否有值或值為 null
。
上述範例也會示範如何在 語句中使用 switch
類型模式,其中變數可能是許多不同類型之一。
如果您想要測試變數是否為指定的類型,但未將它指派給新的變數,您可以使用 is
和 as
運算符作為參考型別和可為 Null 的實值型別。 下列程式代碼示範如何在引進模式比對之前使用 is
屬於 C# 語言的 和 as
語句,以測試變數是否為指定類型:
// Use the is operator to verify the type.
// before performing a cast.
Giraffe g = new();
UseIsOperator(g);
// Use the as operator and test for null
// before referencing the variable.
UseAsOperator(g);
// Use pattern matching to test for null
// before referencing the variable
UsePatternMatchingIs(g);
// Use the as operator to test
// an incompatible type.
SuperNova sn = new();
UseAsOperator(sn);
// Use the as operator with a value type.
// Note the implicit conversion to int? in
// the method body.
int i = 5;
UseAsWithNullable(i);
double d = 9.78654;
UseAsWithNullable(d);
static void UseIsOperator(Animal a)
{
if (a is Mammal)
{
Mammal m = (Mammal)a;
m.Eat();
}
}
static void UsePatternMatchingIs(Animal a)
{
if (a is Mammal m)
{
m.Eat();
}
}
static void UseAsOperator(object o)
{
Mammal? m = o as Mammal;
if (m is not null)
{
Console.WriteLine(m.ToString());
}
else
{
Console.WriteLine($"{o.GetType().Name} is not a Mammal");
}
}
static void UseAsWithNullable(System.ValueType val)
{
int? j = val as int?;
if (j is not null)
{
Console.WriteLine(j);
}
else
{
Console.WriteLine("Could not convert " + val.ToString());
}
}
class Animal
{
public void Eat() => Console.WriteLine("Eating.");
public override string ToString() => "I am an animal.";
}
class Mammal : Animal { }
class Giraffe : Mammal { }
class SuperNova { }
如您所見,藉由比較此程式代碼與模式比對程序代碼,模式比對語法可在單一語句中結合測試和指派,提供更強固的功能。 盡可能使用模式比對語法。