c# 安全地轉換型態技巧
分類
說明
本篇分享一些不錯的,比較安全的轉換型別技巧
string to int
if (int.TryParse(Console.ReadLine(), out int inputNumber))
{
Console.WriteLine($"The number is {inputNumber}");
}
Console.ReadLine()
讀取使用者輸入的字串
然後用 int.TryParse()
解析字串是否可以轉成 int
如果可以的話就將值存入 inputNumber
變數裡
類別階層裡移動
我們先建立有階層的類別
Animal.cs
class Animal
{
public void Eat() { Console.WriteLine("Eating."); }
public override string ToString()
{
return "I am an animal.";
}
}
Mammal.cs
class Mammal : Animal { }
Giraffe.cs
class Giraffe : Mammal { }
SuperNova.cs
class SuperNova { }
接著在主程式示範轉型
為了方便閱讀,我將函式和轉型的範例分開寫
其實都是在同一個檔案 main.cs
使用 is
轉型的部分
main.cs
var g = new Giraffe();
var a = new Animal();
// Eating.
FeedMammals(g);
// Animal is not a Mammal
FeedMammals(a);
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");
}
}
首先看 FeedMammals(Animal a)
這意思是 FeedMammals
的參數 a
要是 Animal
Mammal
繼承 Animal
,所以 Mammal
也是 Animal
這應該可以理解對吧?
函式 FeedMammals()
是只餵食哺乳類動物
所以當 if (a is Mammal m)
成立時,也就是 a
是 Mammal
時(或其子類別)
就會將 a
轉型成 Mammal
指派給 m
接著我們就可以確保使用的是 Mammal m
物件
因為 Mammal
繼承 Animal
,所以一樣有 Eat
方法
Giraffe
繼承 Mammal
FeedMammals(g)
的引數 g
是 Mammal
的子類別,也就是 Mammal
所以會輸出 Eat()
的內容
FeedMammals(a)
的引數 a
是 Animal
,並不是 Mammal
,也不是其子類別
所以會輸出 Animal is not a Mammal
使用 as
轉型的部分
main.cs
SuperNova sn = new SuperNova();
// I am an animal.
TestForMammals(g);
// SuperNova is not a Mammal
TestForMammals(sn);
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");
}
}
接著看 var m = o as Mammal;
意思是如果物件 o
可以轉型成 Mammal
,例如 Mammal
的子類別
就會將 o
轉型為 Mammal
並指派給 m
如果不行就會指派 null 給 m
結果如上註解說明那樣
list 轉型
List 物件有一個 IEnumerable<T> 介面參考
我們可以用此介面來將整個 list 向上轉型
這種作法被稱為共變數(covariance)
以下程式擷取自 Head First C#, 4th Edition Github
Bird.cs
class Bird
{
public string Name { get; set; }
public virtual void Fly(string destination)
{
Console.WriteLine($"{this} is flying to {destination}");
}
public override string ToString()
{
return $"A bird named {Name}";
}
public static void FlyAway(List<Bird> flock, string destination)
{
foreach (Bird bird in flock)
{
bird.Fly(destination);
}
}
}
這是父類別 Bird,下面會建立它的子類別 Duck
Duck.cs
class Duck : Bird
{
public int Size { get; set; }
public KindOfDuck Kind { get; set; }
public override string ToString()
{
return $"A {Size} inch {Kind}";
}
}
Duck 子類別繼承 Bird
Program.cs
List<Duck> ducks = new List<Duck>() {
new Duck() { Kind = KindOfDuck.Mallard, Size = 17 },
new Duck() { Kind = KindOfDuck.Muscovy, Size = 18 },
new Duck() { Kind = KindOfDuck.Loon, Size = 14 },
new Duck() { Kind = KindOfDuck.Muscovy, Size = 11 },
new Duck() { Kind = KindOfDuck.Mallard, Size = 14 },
new Duck() { Kind = KindOfDuck.Loon, Size = 13 },
};
IEnumerable<Bird> upcastDucks = ducks;
Bird.FlyAway(upcastDucks.ToList(), "Minnesota");
當我們建立一個 List<Duck>
時,沒辦法將它做為 Bird.FlyAway()
的第一個引數
因為 Bird.FlyAway()
第一參數要是 List<Bird>
,所以需要將 List<Duck>
轉型成 List<Bird>
你不能用不安全的方式向上轉型 List<Duck>
List<Bird> upcastDucks = ducks;
安全的做法是先將 List<Duck>
向上轉型成 IEnumerable<Bird>
再使用 ToList()
方法將它轉換成 List<Bird>
IEnumerable<Bird> upcastDucks = ducks;
Bird.FlyAway(upcastDucks.ToList(), "Minnesota");
參考
一杯咖啡的力量,勝過千言萬語的感謝。
支持我一杯咖啡,讓我繼續創作優質內容,與您分享更多知識與樂趣!