在某些情況下,我們會想知道自己的程式碼被誰所呼叫,例如: 當某個共用函數發生錯誤時,若可知是哪一個類別呼叫這個函數時出錯,將十分有助於Debug。

各位應該都看過.NET Debug Build在出錯時,會顯示所謂的Call Stack(即Exception物件的StackTrace屬性),例如:
X:\>labs.exe
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.

   at Labs.Program.Lab0818() in F:\Documents and Settings\jeffrey\My Documents\V

isual Studio 2005\Projects\Labs\Labs\Program.cs:line 295

   at Labs.Program.Main(String[] args) in F:\Documents and Settings\jeffrey\My D

ocuments\Visual Studio 2005\Projects\Labs\Labs\Program.cs:line 304

那我們可以自己取得這些資訊嗎?

配合System.Diagnostics及System.Reflection的一些類別,這個理想是可能實現的!

我寫了一個簡單的範例:

class Caller
{

    public Caller() { }

    public void CallIt() 

    { Tracer.ShowCallerInfo("Called by Caller object"); }

}

class Tracer

{

    public static void ShowCallerInfo(string remark) 

    {

        Console.Write(new string('=', 80));

        Console.WriteLine("Caller Remark: {0}", remark);

        StackTrace st = new StackTrace(true);

        StackFrame sf = st.GetFrame(1);

        MethodBase mb = sf.GetMethod();

        Console.WriteLine("Caller Module: {0}",mb.Module.FullyQualifiedName);

        Console.WriteLine("Caller Class & Method: {0}.{1}()", mb.ReflectedType.FullName, mb.Name);

        Console.WriteLine("File Info: Line {0} in {1}", sf.GetFileLineNumber(), sf.GetFileName());

        Console.WriteLine();

    }

}

然後,直接在Console Application呼叫及建立Caller物件後呼叫


static void Lab0818()
{

    Console.WriteLine(calcDiv(1, 0));

    Tracer.ShowCallerInfo("Called by main.cs");

    Caller c = new Caller();

    c.CallIt();

}

可以得到以下的執行結果:


X:\>labs.exe
================================================================

Caller Remark: Called by main.cs

Caller Module: X:\Labs.exe

Caller Class & Method: Labs.Program.Lab0818()

File Info: Line 290 in F:\Documents and Settings\jeffrey\My Documents\Visual Stu
dio 2005\Projects\Labs\Labs\Program.cs

================================================================
Caller Remark: Called by Caller object
Caller Module: X:\Labs.exe

Caller Class & Method: Labs.Caller.CallIt()

File Info: Line 15 in F:\Documents and Settings\jeffrey\My Documents\Visual Stud
io 2005\Projects\Labs\Labs\Tracer.cs

瞧! 我們自己也有能力取得呼叫者的相關資訊。不過,要注意以下幾點:


1.        不管是Debug Build或Release Build,我們都可以取得呼叫者的程序、類別、Method等資料,但必須有.pdb檔時,才能顯示出在哪個原始檔(.cs)的哪一列

2.        Debug Build沒有pdb時,無法顯示原始檔及所在程式列。

3.        Release Build經設定也可產生pdb。

4.        上述的程式碼中,使用了Reflection的技巧去取得呼叫者資訊,不利於效能,建議節制使用。

Comments

# by wilson

我想請問一下有何方式可以在 unmanged dll 知道Caller 的manged Dll information(如 版本,public key 等等)?

Post a comment