Visual Studio 調試技巧


寫在前面:假定你在日常的工作中使用到了Visual Studio,並期望了解一些調試技巧來提高工作效率,也許本文適合你。以下Visual Studio簡稱vs。

一、入門

以最簡單的控制台應用程序為例,代碼如下:

 1 class Program
 2 { 3 static void Main(string[] args) 4  { 5 int result = Sum(2, 3); 6 Console.WriteLine("2+3={0}", result); 7  } 8 9 private static int Sum(int a,int b) 10  { 11 return a + b; 12  } 13 }

調試的根本目的是跟蹤代碼、程序的狀態,判斷是否按照期望的行為運行。常用的跟蹤手段有控制台輸出、日志輸出以及斷點調試。

  1. 控制台輸出用於開發環境,可以在vs輸出窗口中查看程序輸出的內容如下圖所示:

由於是控制台應用程序,Console.WriteLine() 輸出的內容不會顯示在輸出窗口,故采用Trace.WriteLine() 。對非控制台應用程序,Console.WriteLine() 輸出的內容會正常顯示在輸出窗口。

2. 日志輸出用於開發環境和生產環境,但更多用於生產環境,用來收集程序的運行信息。常用的日志組件有Log4Net、NLog以及自定義日志組件。依據問題嚴重程度大致分為嚴重錯誤、錯誤、警告、信息以及調試信息等幾個級別。可結合實際需求靈活配置。

3. 斷點調試多用於開發環境,通過設置斷點,讓程序在指定的位置暫停,以便觀察上下文環境情況。

以上圖為例,添加斷點后,鼠標移動到變量名上,可以觀察一些變量的值。對於復雜類型的變量,通過選中變量,右鍵選擇快速監視的方式。避免鼠標移動后,監視的信息消失。

以上三種調試方法中,對於開發環境而言,使用最為頻繁的方法當數斷點調試。后面以斷點調試為主,深入介紹。

二、進階

  • 啟動外部程序

要使用斷點調試,需要滿足一些斷點調試的條件。對於可執行程序,如控制台應用程序、窗體應用程序、WPF應用程序以及Web應用程序,啟動調試后,可以在期望的位置添加斷點。而對於如動態庫類型,不可以直接啟動調試。想要調試這類項目,有兩種方式。一種是可以設置項目屬性中的啟動操作,指定引用該動態庫的可執行程序路徑。

另一種方式是運行調用了動態庫的可執行程序,通過附加可執行程序進程的方式來調試。

  • 附加進程

新建 DllDemo 動態庫項目,添加 MyMath 類,添加靜態方法 Max(int a,int b) 。代碼如下:

 1 using System;
 2 
 3 namespace DllDemo 4 { 5 public class MyMath 6  { 7 public static int Max(int a,int b) 8  { 9 return Math.Max(a, b); 10  } 11  } 12 }

 添加對 DllDemo 動態庫項目引用, 並修改控制台應用程序如下。為了方便后續調試,控制台應用程序中添加 Console.Read()。

 1 using DllDemo;
 2 using System; 3 using System.Diagnostics; 4 5 namespace DebugDemo 6 { 7 class Program 8  { 9 static void Main(string[] args) 10  { 11 Console.WriteLine("等待鍵盤輸入..."); 12 13  Console.Read(); 14 15 int result = Sum(2, 3); 16 17 Console.WriteLine(string.Format("2+3={0}", result)); 18 19 result = MyMath.Max(2, 3); 20 21 Console.WriteLine(string.Format("MyMath.Max(2, 3)={0}", result)); 22  } 23 24 private static int Sum(int a, int b) 25  { 26 return a + b; 27  } 28  } 29 }

運行控制台應用程序DebugDemo.exe ,附加該進程,在合適的位置添加斷點。

  • 條件斷點

在多層循環中,有時想要滿足一定條件時命中斷點。這時,條件斷點會比較有效。以下面代碼為例,想要index = 10(number > 10)時命中斷點。

private int Sum(int number)
{
    int result = 0;

    for(int index= 0;index<number;index++)
    {
        result += index;
    }

    return result;
}

在合適的位置,按下F9設置斷點。右鍵紅色的斷點,選擇條件...,在條件中輸入 index == 10 然后關閉。運行程序進入循環體后,會在index = 10時,命中斷點

  • 即時窗口

有時,當程序運行起來后,進入了某種上下文環境中。此時,想要跟蹤程序在另一種上下文環境的運行情況,可以在即時窗口中直接設置某些上下文環境。代碼如下所示:

internal class People
{
    public string Name { get; set; }
    public bool IsMale { get; set; }
}

static void Main(string[] args)
{
    PrintSex(new People() { Name = "張三",IsMale =true});
}

private static void PrintSex(People people)
{
    if (people.IsMale)
    {
        Console.WriteLine("{0} is 男性", people.Name);
    }
    else
    {
        Console.WriteLine("{0} is 女性", people.Name);
    }
}

程序運行以后,會進入people為男性的分支。在 if (people.IsMale) 行設置斷點,當進入斷點以后,在即時窗口中更改 people.IsMale 的值后按下Enter鍵執行,使程序進入另一個分支。

  • 更改執行順序

以即時窗口涉及到的代碼為例,無論上下文環境如何,想要直接進入 people.IsMale 的分支,可在if (people.IsMale) 行設置斷點。進入斷點后,在紅色斷點處。直接按住鼠標左鍵,拖動到 Console.WriteLine("{0} is 女性", people.Name); 行,進入該分支。

  • 查看調用堆棧

當程序包含接口繼承、抽象類繼承等邏輯,導致結構過於復雜,知道功能入口以及出口,想要了解過程時,調用堆棧會比較有用。以下面代碼為例:

private static void DoWork()
{
    DoWork1();
}

private static void DoWork1() { DoWork2(); } private static void DoWork2() { DoWork3(); } private static void DoWork3() { Console.Write("DoWork3"); }

假設知道功能入口為DoWork,功能結果為DoWork3,想要了解DoWork3的調用邏輯,可以在DoWork3中設置斷點,啟動調試后打開調用堆棧窗口,如下圖:

  • 異常設置

當程序運行以后,結果不是預期的。初步猜測發生了異常,由於某些原因,捕獲了異常,卻未妥善處理,導致異常信息被“吞”掉。此時,異常設置會格外有效。以下面代碼為例:

private static void TryToDivideByZero()
{
    try { int a = 9; int b = 0; int c = a / b; } catch(Exception ex) { Console.WriteLine(ex.Message); } }

由於方法中存在異常,又有異常捕獲,后續邏輯會被打斷,此時對異常設置做如下設置:

重新調試程序會有如下結果,方便快速定位異常發生點。

三、高級

在某些場景下,開發環境運行正常,非開發環境運行異常,依賴常規手段無法定位問題原因,想要斷點調試,非開發環境運行缺少VS時,遠程調試會比較有效。

在VS安裝目錄下拷貝遠程調試所需的文件夾x86,x64到非開發環境

依據遠程目標機系統環境,運行x86/x64文件夾下msvsmon.exe,選擇工具中的選項菜單做如下配置:

運行待調試程序后,在VS中選擇調試>附加到進程(ctrl+alt+p),設置連接類型,連接目標(遠程ip地址或計算機名)后查找,會自動列出相關內容。

在可用進程中選擇對應的進程

在合適的位置添加斷點即可開始調試了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM