2021-10-14

Exception 是傳遞訊息的通道

void show(string tag)
{
    Console.WriteLine(tag);
}

void methodA()
{
    throw new Exception("error msg");
    show("A");
}

void methodB()
{
    methodA();
    show("B");
}

void methodC()
{
    try
    {
        methodB();
        show("C");
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

這裡為了方便我們理解將程式展開成下面的樣子:

void show(string tag)
{
    Console.WriteLine(tag);
}

void methodC()
{
    try
    {
        methodB();
            void methodB()
            {
                methodA();
                    void methodA()
                    {
                        throw new Exception("error msg");
    //-----------------------------------------------------
                        show("A");
                    }
                show("B");
            }
        show("C");
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

從範例中我們可以看出兩個特性:


* 通透性

從 throw 的那一行開始 Exception 會一直向上傳遞,直到 catch 的區段。


* 脫離性

從 throw 的那一行之後的程式都不會被執行,會有類似 return 的效果,不同的是會對每一層的 method 都進行脫離,包含 try 的區段也會脫離。


methodC 的 catch 會捕獲從 methodA 丟出的 Exception,並且 Exception 中的 StackTrace 會紀錄 methodA, methodB, methodC,而 show() 都不會被執行。

由於大部分的程式邏輯都可以轉化成 else 就離開的程式流程,正好符合 throw 的脫離性,所以我們一開始在撰寫程式邏輯的時候,可以先專注在一般正常的流程邏輯上,之後再去補足檢查邏輯或脫離邏輯,最後在合適的位置進行 try catch 處理,或者在全域的錯誤處理中進行處理。


這裡有一個糟糕的 method,他用了個 Result 物件來裝載回傳結果以及錯誤訊息:

public class Result
{
    public int Value { get; set; }
    public string Error { get; set; }
}

public Result BadMethod(int input)
{
    var result = new Result();

    if (input > 0)
    {
        result.Value = 100 / input;
    }
    else
    {
        result.Error = "input 需要大於零";
    }
    return result;
}

如果用 Exception 可以讓程式簡單很多:

public int GoodMethod(int input)
{
    if (input <= 0)
    {
        throw new Exception("input 需要大於零");
    }

    return 100 / input;
}

沒有留言:

張貼留言

你好!歡迎你在我的 Blog 上留下你寶貴的意見。