1. 程式人生 > >Try-Catch無法正確定位異常位置,我推薦2個有效技巧

Try-Catch無法正確定位異常位置,我推薦2個有效技巧

宇宙第一開發IDE Visual Studio的除錯功能非常強大,平常工作debug幫助我們解決不少問題。今天分享兩個異常捕獲的技巧,希望能夠幫助解決一些問題。
以下兩種情況,我相信大家都會遇到過。

  • 1.沒有使用Try-Catch語句,當異常發生的時候,能夠自動跳轉到異常發生的地方,在使用Try-Catch捕獲異常的時候,直接跳轉到Catch語句的位置,並不會自動定位到異常程式碼的位置。
  • 2.使用Try-Catch的時候,多層方法呼叫時,並不能直接檢視到異常程式碼的位置。

技巧1:自動定位到異常程式碼位置

針對問題1,我們最想要的結果是,哪裡有程式碼出現錯誤了,就直接定位到哪兒,異常出在哪行程式碼上,我一眼就能看得出,這樣就能更快地處理問題了。

對於問題1,所出現的這種情況,簡單復現一下一個空引用的異常

namespace ExceptionSample
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Random random = null;
                Console.WriteLine(random.Next());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            Console.ReadLine();
        }
     }
}     

上面的異常程式碼NullReferrenceException,Debug模式下,會跳轉到catch語句這裡。你可能覺得這挺簡單的......可實際實際工作中,你的一個方法中僅僅只這一個物件嗎?

在實際工作中可能不止random一個物件,程式碼複雜,物件夠多,幾十個也有,我們就很難定位到異常出錯的程式碼了。StackTrace可以定位到那個函式呼叫錯了,並不能定位到哪一行程式碼出錯了。
為了解決這個行為可以通過在Visual Studio中選單欄中的除錯》視窗》異常設定中去配置。如下圖所示:

勾選上Common Language Runtime Exceptions下列的異常單選框。有點多,以前的設定有些變化。

現在我們再看之前的程式碼,使用Try-Catch語句捕獲異常的時候,就會直接定位到異常程式碼的位置了,如下圖示:

       static void Main(string[] args)
        {
            try
            {
                Random random = null;
                Random random1 = new Random();
                Random random2 = new Random();
                Random random3 = new Random();
                Console.WriteLine(random1.Next());
                Console.WriteLine(random2.Next());
                Console.WriteLine(random3.Next());
                Console.WriteLine(random.Next());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            Console.ReadLine();
        }

技巧2:正常的throw 姿勢

還是之前的一個方法,我已經將異常設定回覆默認了。

        static void Main(string[] args)
        {
            try
            {
                Random random = null;
                Console.WriteLine(random.Next());
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.Write(ex);
                throw ex;
            }
        }

我們再輸出中可以看到(ps:專案名稱用的之前的,不介意哈)

錯誤的程式碼在16行。可實際工作中的情況並不是這樣簡單,基本上是A方法呼叫B方法,B方法呼叫C方法,程式碼如下所示:
在Main方法中呼叫ThrowNullReferrence(),方法ThrowNullReferrence中呼叫SetNullReferrence()。程式碼變複雜後,一層巢狀一層。這個時候能正確顯示出程式碼異常的位置嗎?

        static void Main(string[] args)
        {
            try
            {
                ThrowNullReferrence();
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.Write(ex);
                throw ex;
            }
        }
        public  static void ThrowNullReferrence()
        {
            try
            {
                SetNullReferrence();
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.Write(ex);
                throw ex;
            }
        }
        public static void SetNullReferrence()
        {
            try {
                Random random = null;
                Console.WriteLine(random.Next());
            }
            catch(Exception ex)
            {
                System.Diagnostics.Debug.Write(ex);
                throw ex;
            }
        }

我們可以通過下圖看到:

System.NullReferenceException: 未將物件引用設定到物件的例項。
在 ExceptionSample.Program.SetNullReferrence() 位置 D:\Learn\延遲載入\LinqLayzLoad\LinqLayzLoad\Program.cs:行號 39System.NullReferenceException: 未將物件引用設定到物件的例項。
在 ExceptionSample.Program.SetNullReferrence() 位置 D:\Learn\延遲載入\LinqLayzLoad\LinqLayzLoad\Program.cs:行號 44
在 ExceptionSample.Program.ThrowNullReferrence() 位置 D:\Learn\延遲載入\LinqLayzLoad\LinqLayzLoad\Program.cs:行號 27System.NullReferenceException: 未將物件引用設定到物件的例項。
在 ExceptionSample.Program.ThrowNullReferrence() 位置 D:\Learn\延遲載入\LinqLayzLoad\LinqLayzLoad\Program.cs:行號 32
在 ExceptionSample.Program.Main(String[] args) 位置 D:\Learn\延遲載入\LinqLayzLoad\LinqLayzLoad\Program.cs:行號 15

錯誤程式碼的位置在39行,以上出現異常的地方都是throw的位置。
原因呢?
catch捕獲完後,如果要向上丟擲,應該重新例項化一個新的異常物件,再向上丟擲,這個最外層方法catch到的才是完整的異常,當然也包括完整的堆疊資訊,這樣才能定位到異常程式碼的位置。
要使用 throw new Exception
改造後的例子如圖,精準定位到
39行的空引用異常
Console.WriteLine(random.Next());

結語

分享之前看到的一個老程式設計師的經驗之談:“多coding,少debug