標籤:
一個好的調試器,能夠協助程式員處理很多自動化的工作。試想下列的情形:
- 錯誤是發生在一個迴圈當中,只在迴圈遍曆了若干次以後,才會出現。
- 錯誤只在程式中某個變數為一個特定的值,才會出現,而這個變數的值是在程式啟動並執行過程中隨機設定的。
- 多個線程都要調用同一個函數,而你只想在某幾個線程執行這個函數的時候,中斷程式的執行。
在上面列出來幾種情況當中,如果調試器不能提供一個有效方法協助我們設定斷點的話,調試這種程式將會是很痛苦的一件事。在第一種情況當中,使用者不得不在迴圈中設定斷點,並且要記住自己按下F5的次數,1,2,3…,499,300,301…。第二種情況下,使用者還得靠一些運氣成分才能發現錯誤原因。
CLR Debugger的開發人員正是考慮到以上情形,給CLR Debugger添加了這些功能,條件斷點(Conditional Breakpoint)和斷點過濾器(Breakpoint Filters)。
1.1.1. 根據斷點的觸發次數中斷程式的執行
條件斷點允許你設定程式在斷點處中斷的條件,你可以設定斷點在觸發若干次以後,調試器才中斷程式的執行,也可以設定調試器根據一條返回布爾值的語句來中斷程式的執行。我將以下面的程式為例,講解如何設定條件斷點:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 |
using System;
public class ConditionalBreakpoint
{
public static void Main()
{
Random random = new Random();
int k = 0;
for (int i = 0; i < 100; ++i)
{
int j = random.Next();
if (i % 4 == 0)
k = i;
Console.WriteLine("{0} + {1} = {2}", i, j, i + j);
}
}
} |
表 1-3 條件斷點的示範代碼
在程式的第14行設定斷點,在CLR Debugger底部的“Breakpoints”視窗中右鍵點擊剛剛設定的斷點,在右鍵菜單裡面選擇“Hit Count…”菜單,出現所示的“Breakpoint Hit Count”對話方塊
圖 1-7“Breakpoint Hit Count”對話方塊
在圖1-7中,CLR Debugger允許使用者佈建4種根據斷點觸發次數中斷程式的條件,第一種是預設的“總是中斷”情形;第二種設定“只在斷點觸發了若干次以後才中斷程式”的情形;第三種設定“只在斷點的觸發次數是若干次的倍數時才中斷程式”的情形;第四種設定“當斷點出發了若干次以後才中斷程式”的情形。
1.1.2. 設定布爾條件中斷程式的執行
在表1-3中的程式裡,我們看到程式在迴圈裡面隨機設定變數j的值,為了只在j等於某個特定值中斷程式的執行,我們需要這樣做:
在程式的第14行設定斷點,在CLR Debugger底部的“Breakpoints”視窗中右鍵點擊剛剛設定的斷點,在右鍵菜單裡面選擇“Condition…”菜單,出現所示的“Breakpoint Condition”對話方塊:
圖 1-8“Breakpoint Condition”對話方塊
CLR Debugger裡面內建了一個運算式解譯器,因此當你選擇了“Is true”單選框後,可以在“Breakpoint Condition”的“Condition”文字框裡面設定一些比較複雜的布爾條件運算式—運算式的文法與C#的文法相同。
而如果你選擇的是“Has changed”單選框,這時你不僅可以跟蹤某個變數的值是否已經更改了,而且還可以跟蹤某個運算式的值是否已經更改了。有興趣的讀者可以將“Condition”文字框的值設定成“k”和“k > 28”,然後分別使用這兩個條件斷點啟動程式,在“Watch”視窗中觀察變數“i”的值,來感受CLR Debugger強大的條件斷點設定功能。
1.1.3. 只允許斷點在某個線程中才能被觸發
通常來說,當你在某個函數裡設定了斷點以後,無論是哪一個線程執行到斷點處,都會觸發斷點,根據斷點的條件中斷程式的執行。但是 CLR Debugger允許你只在某個線程中設定斷點,當你在調試器裡面同時調試兩個以上的程式時,CLR Debugger甚至還允許設定斷點在哪一個程式中起作用。
在CLR Debugger底部的“Breakpoints”視窗中右鍵點擊一個要過濾的斷點,在右鍵菜單裡面選擇“Filter…”菜單,出現所示的“Breakpoint Filter”對話方塊:
圖 1-9 “Breakpoint Filter”對話方塊
正如在“Breakpoint Filter”對話方塊中描述的那樣,在“Filter”文字框裡面,你只可以設定在哪一台機器上、哪一個程式和哪一個線程中設定斷點。根據調試機器名來設定斷點是為了支援遠端偵錯,遠端偵錯將在本章後面講解。
5個屬性,ThreadId需要特別說明一下,ThreadId並不是託管程式中,.NET 架構中System.Threading.Thread.ManagedThreadId,兩者不能等同。簡單來說,ManagedThreadId是線程在CLR中的標識符,而ThreadId卻是線程在作業系統中的標識符。因此ThreadId需要從調試器中的“Threads”視窗中擷取。
斷點的使用
叫用次數(Hit Counts)
右擊斷點,可以設定Hit Counts(叫用次數),會彈出如下的對話方塊
當條件滿足的時候斷點會被命中(即即將被執行),這個叫用次數是斷點被命中的次數。預設是始終break,選項有如下的幾種:始終break;當叫用次數達到多少次時break;當叫用次數是多少的倍數時break;當叫用次數大於等於多少的時候break。
於是在上篇中的條件也可以這樣實現,設定叫用次數等於50的時候break,按F5後,斷點被觸發,此時i=50。
斷點過濾器
我們可以限制斷點在特定的處理器和進程中。可以設定機器名、進程id、進程名、線程id、線程名中的某些條件來過濾一些斷點。
注意:ThreadId需要特別說明一下,ThreadId並不是託管程式中,.NET 架構中System.Threading.Thread.ManagedThreadId,兩者不能等同。簡單來說,ManagedThreadId是線程在CLR中的標識符,而ThreadId卻是線程在作業系統中的標識符。因此ThreadId需要從調試器中的“Threads”視窗中擷取。
斷點條件
我們可以設定斷點達到的條件,如,我們設定運算式為i==5(注意是判相等,而不是賦值的等於),按F5,斷點再次被觸發,此時i=50。
還有一個選項是已經被改變,則裡麵條件是具體的變數,如我們的代碼如下
private void ConditionDebug()
{
int hitCount = 0;
for (int i = 0; i < 100; i++)
{
if (i==49)
{
hitCount = 1;
}
}
Console.Write("Hit Count={0}", hitCount);
}
我們在代碼裡如果i==49,就將hitCount的值改變,同時設定斷點的條件為
則當斷點再次被觸發的時候此時i=50。這個通常被用在找變數的時在什麼時候發生改變。
斷點的位置
可以設定斷點的位置,如,設定程式到達那個檔案的第幾行第幾個字元時觸發斷點。
斷點觸發時…
我們可以設定斷點到達時做一些其他的事情,如列印訊息,運行一個宏。
自訂呼叫堆疊
堆疊追蹤時vs一步步執行你的程式是對當前的方法調用繼承關係的直觀顯示。在偵錯工具時,我們會經過一個又一個方法,包括方法的嵌套調用。堆疊追蹤會對這當中的每一層方法作出記錄。選擇“調試-->視窗-->呼叫堆疊”,或者是快速鍵Ctrl+Alt+C就可以看到當前的堆疊追蹤狀態。這裡會將每個方法單獨顯示為一行,並且帶有行號和參數值。每一個新的方法調用被稱為堆疊框架。
堆疊追蹤是廣為人知的調試工具,它的優點在於你可以雙擊任意一行跳轉到程式中該層調用方法的代碼。於是你可以看到程式是如何執行到這一位置的,同時可以看到方法接受的參數值。並且可以使用Ctrl+C將一個或者全部堆疊框架複製到剪貼簿,並將這個方法的調用資訊發送給工作夥伴。
項目屬性中的Debug選項卡
如果你的項目是Console項目(控制台應用程式)或者是WinForm項目,則右擊項目解決方案,選擇屬性,會出來如下的項目屬性表單。
我們可以設定“啟動動作”、“啟動選項”和“是否啟用調試”。
Start Action有三個選擇項:
Start Project:預設選項,設定為啟動項目
Start external program:調試的時候啟動內部程式
Start browser with URL:調試的時候開啟URL地址
使用Trace.axd調試ASP.NET
在以前asp時候,我們為了查看某個變數的值,通常會使用Response.Write方法。可能現在許多ASP.NET程式員也習慣在後台使用Response.Write方法將變數的值寫出來,其實微軟提供了很好的調試工具,即Trace.axd。它的功能主要是:配置 ASP.NET 代碼Tracing Service以控制如何收集、儲存和顯示跟蹤結果。
關鍵的幾個選項:
1、localOnly 預設為false。這個很好理解。如果為true,只在本地輸出跟蹤資訊。
2、enabled 是否啟用跟蹤。
3、pageOutput 指定在每一頁的結尾是否呈現跟蹤輸出。如果是 false ,則只能通過跟蹤工具 + 生產力訪問跟蹤輸出。
4、requestLimit 指定在伺服器上儲存的跟蹤請求的數目。最大為10000,預設為10
5、traceMode 指定顯示跟蹤資訊的順序。SortByCategory或 SortByTime(預設)
關於更多可以參考
http://msdn.microsoft.com/zh-cn/library/6915t83k%28VS.80%29.aspx
下面以一個小Demo來說明怎麼使用Trace.axd來調試ASP.NET
1. 建立一個Web項目,取名為WebTraceTest
2. 編輯web.config檔案,添加trace節點(在)
內容如下:
<trace enabled="true" localOnly="true"
pageOutput="true"
requestLimit="15"
mostRecent="true" />
3. 建立一個頁面,取名為Test.aspx,在裡面增加一個文字框和一個按鈕(都是伺服器端的控制項)
按下F5,開始調試,會發現出現如下介面
5. 在文字框中輸入文字,如Alexis,點擊按鈕,會發現Form Collection中會有詳細的資訊,如下:
說明:使用Trace.axd我們可以獲得以下資訊:
Request Details:請求的詳細資料
Trace Information:跟蹤資訊
Control Tree:控制項樹
Session State:工作階段狀態
Application State:應用程式狀態
Request Cookies Collection:請求Cookie集合
Response Cookies Collection:響應Cookie集合
Headers Collection:標題集合
Response Headers Collection:響應標題集合
Form Collection:表單集合
Querystring Collection:QueryString集合(即Url中?後面的字串的資訊)
Server Variables:伺服器變數
將Visual Studio與一個運行中的進程串連
當你按下F5對程式開始調試時,VS.NET會對項目進行產生(如果有必要的話)並以偵錯模式啟動程式。也就是說,只要項目位於debug版本的程式集中,VS.NET就與運行得程式之間建立了串連,以便對斷點等與調試相關的方法作出反應。
不過有些時候,我們需要或者想要對正在運行得Visual Studio之外啟動的進程進行調試。當進程位於debug版本的程式集中,這是可以做到的。
1. 選擇“工具—>調試進程”列出所有正在運行得程式,如
2. 選擇自己感興趣的進程,點擊串連,此時Visual Studio自動切換到了偵錯模式。
3. 開啟Progress視窗,發現我們剛剛選擇的進程在列表中,如
這一技巧可以讓你對Windows服務進程進行調試。編寫Windows服務進程時,你無法按F5啟動調試,因為它們必須先通過管理工具安裝後啟動才能運行。如果你在偵錯模式下產生並安裝服務程式,就可以使用這一技巧進行調試。
而且你可以對SQL預存程序使用同樣的方式進行調試。如果你安裝了SQL Server調試組件,並且有足夠的許可權,就可以串連到SQL Server的進程,並在伺服器中為預存程序設定斷點來一步步執行。
調試Visual Studio中的多重專案
在實際開發中,我們往往分了許多層,有許多的項目集合在一個解決方案下。我們可以右擊要調試的項目選擇“調試-->運行新執行個體”來實現調試這個項目。我也可以右擊解決方案,選擇多項目調試,如
我們還可以設定項目的期待順序。在用戶端/伺服器(CS結構)程式中,我們可以使用這一方法來確保伺服器端程式在用戶端程式之前運行。
只在特定類型的異常時中斷
一個健壯的程式會在運行時處理所有可能出現的異常。不過開發人員在調試複雜的程式時會覺得這樣有些麻煩。因為所有的異常都被處理掉了。在出現任何異常時,Visual Studio不會再進行處理,或者中斷代碼來對使用者作出提示。
幸運的是Visual Studio有個選項可以讓開發人員指定他們關心的異常類型。選擇功能表列à調試à異常,或者使用快速鍵Ctrl+Alt+E。如
我們可以看到一個樹狀結構列出所有VS可以監視到的異常。
後面的兩個勾選框的意思分別為是否被拋出和使用者是否不處理。
參考:
《Visual Studio.NET提示手冊》
http://msdn.microsoft.com/
調試時設定條件斷點