c# 安全地轉換型態技巧


分類

建立時間: 2022年10月10日 02:30
更新時間: 2022年11月1日 16:14

說明

本篇分享一些不錯的,比較安全的轉換型別技巧

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) 成立時,也就是 aMammal 時(或其子類別)
就會將 a 轉型成 Mammal 指派給 m
接著我們就可以確保使用的是 Mammal m 物件
因為 Mammal 繼承 Animal,所以一樣有 Eat 方法

Giraffe 繼承 Mammal
FeedMammals(g) 的引數 gMammal 的子類別,也就是 Mammal
所以會輸出 Eat() 的內容

FeedMammals(a) 的引數 aAnimal,並不是 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");

參考

觀看次數: 874
asc#covarianceislisttype轉型
按讚追蹤 Enjoy 軟體 Facebook 粉絲專頁
每週分享資訊技術

一杯咖啡的力量,勝過千言萬語的感謝。

支持我一杯咖啡,讓我繼續創作優質內容,與您分享更多知識與樂趣!