09 五月, 2012 16:22
1.源由
在實務上,一支應用程式偶而會出現難以想像的錯誤情境,這情境在意料之外所以沒有預防,也不知為何會出現。
這時「偵錯模式」就派上用場了。以偵錯模式來追蹤問題的起源,找出問題根結後,答案也就不遠了。
「偵錯模式」設計目地在於偵察問題所在。其實這個模式本身是自我矛盾的。應用程式本身是無法自我偵錯的,那到底是如何偵錯的?方法就是加入“額外的程式碼”在關鍵的關卡紀錄(logging)執行了什麼程序、紀錄進出了什麼資料。再由這些紀錄去看問題的位置,去查出問題的原因。
2.目的, spec. statement.
試寫應用程式偵錯模式。
模擬一應用程式的組織,含蓋了主模組與副模組,與副模組的連結方式有靜態參考(static reference)與動態參考(dynamc reference)方式連結,如下圖:
此例中:
主模組:conApp_TraceLab.exe
副模組一:ClassLibrary1.dll,以靜態參考方式連結。
副模組二:ClassLibrary2.dll,以動態參考方式連結。
在主模組設定成 Trace mode,在副模組會有效碼?答案是:有效。
3.解法, solution
偵錯模式是古老就有的議題,各個開發程式的供應商早有解了。在微軟的 .Net Framework 其解法就是「System.Diagnostics」,此命名空間專門處理系統診斷的工作。我們使用其中的「Trace」類別來實作偵錯模式。
「Trace」類別的用處其實很廣泛,但不在此文章討論範圍內,故不提了。
4.原碼
以下為本人練習原碼摘錄:
使用開發工具是 VS2010,此 Lab 的原始碼並不大,故把全部都放上。
先看一下方案總管:
其中主模組的參考了 ClassLibrary1,但沒有ClassLibrary2。
ClassLibrary2 將以 Reflection技術 參考進來。
再看原始碼,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace ClassLibrary1
{
public class Class1
{
public static void CallMe()
{
// go
Console.WriteLine("Hello world. in ClassLibrary1.");
Trace.WriteLine("I am in TRACE mode. in ClassLibrary1.");
Console.WriteLine("Good bye. in ClassLibrary1.");
}
}
}
上面是ClassLibrary1,下面是ClassLibrary2,兩邊的碼是一樣的。都是只say hello 就離開了,不過在中間加入「Trace」函式做紀錄。且都沒有設定成偵錯模式的碼,因為這部份是主模組的工作。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace ClassLibrary2
{
public class Class2
{
public static void CallMe()
{
// go
Console.WriteLine("Hello world. in ClassLibrary2.");
Trace.WriteLine("I am in TRACE mode. in ClassLibrary2.");
Console.WriteLine("Good bye. in ClassLibrary2.");
}
}
}
下面是主模組程式原始碼。其中 ClassLibrary1 是靜態參考可以直接叫用, ClassLibrary2 是動態參考需繞一下再 Invoke 才行。
其中關鍵之一,設成偵錯模組的程式碼只須一行:
Trace.Listeners.Add(new ConsoleTraceListener());
其原理什麼的實在懶得講…其實是量很多講不完…請自行補充。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Reflection;
namespace conApp_TraceLab
{
class Program
{
static void Main(string[] args)
{
#region ## parsing the arguments.
bool _TRACE = false;
foreach (var arg in args)
{
switch (arg)
{
case "/TRACE":
case "/t":
_TRACE = true;
break;
}
}
#endregion// set up the running mode.
if(_TRACE)
Trace.Listeners.Add(new ConsoleTraceListener());// go
Console.WriteLine("Hello world.");
Trace.WriteLine("I am in TRACE mode.");
Console.WriteLine("Good bye.");// call static module function.
ClassLibrary1.Class1.CallMe();// call dynamic module function.
Assembly lib2 = Assembly.LoadFrom("ClassLibrary2.dll");
Type class2 = lib2.GetType("ClassLibrary2.Class2", true);
class2.InvokeMember("CallMe", BindingFlags.InvokeMethod, null, null, null);
}
}
}
5.執行結果
附上執行結果。
先以一般模式執行,無 Trace 輸出。
再以 /TRACE 模式執行,有 Trace 輸出。
(完)
推文( 0 )





