2017-02-22 53 views
1

我有下面的代碼的調試信息在調試模式下時,添加到一條消息:運行期間何時發生方法解析/查找?

代碼在測試DLL

private string GetMessage(Foo foo) 
{ 
    var messageBuilder = new StringBuilder(); 

    // add message info 

#if DEBUG 
    messageBuilder.AppendLine(foo.GetDebuggingInfo()); 
#endif 

    return messageBuilder.ToString(); 
} 

圖書館在測試

C++庫從C#叫通過託管C++包裝項目

#ifdef DEBUG 
string Foo::GetDebuggingInfo() 
{ 
    ... 
} 
#endif 

現在我跑進是Foo在單獨的庫中聲明的問題,GetDebuggingInfo也有條件地編譯。而爲了向後兼容測試儀DLL是對圖書館的所有以前發佈的版本上運行的測試,以確保輸出我們的服務器發送將繼續按預期在所有不同版本的客戶端中被攝取。測試代碼然後被複制到一個文件夾,以及要測試的庫的期望版本,而不是測試人員編譯的版本。一切都運行良好,直到我的代碼達到GetMessage,那就是當我遇到MethodNotFoundException

我的第一個解決這個嘗試,我想使用反射,以確保該函數存在的調用函數之前,像這樣:

#if DEBUG 
    if (foo.GetType().GetMethod("GetDebuggingInfo", BindingFlags.Instance | BindingFlags.Public) != null) 
     messageBuilder.AppendLine(foo.GetDebuggingInfo()); 
#endif 

我估計會保持該方法被調用,即使測試器DLL是一個調試版本,測試下的DLL是一個發佈版本。仍是同樣的問題。添加了一些額外的跟蹤調試語句後,我發現GetMessage甚至沒有被輸入。在意識到這一點後,我嘗試將有問題的方法調用移入它自己的函數中,並且一切正常。

#if DEBUG 
    // reflection check remains to keep the call from blowing 
    // up when Tester is DEBUG and Under Test is RELEASE 
    if (foo.GetType().GetMethod("GetDebuggingInfo", BindingFlags.Instance | BindingFlags.Public) != null) 
     AddDebuggingInfo(messageBuilder, foo); 
#endif 

#if DEBUG 
private void AddDebuggingInfo(StringBuilder messageBuilder, Foo foo) => 
    messageBuilder.AppendLine(foo.GetDebuggingInfo()); 
#endif 

所以,即使我有我需要一個有效的解決方案,我不明白我的最終解決方案是如何工作的,當我想通了反映檢查就已經足夠了,從扔MethodNotFoundException保持代碼。所以在運行時,何時查找和解決了方法?

+0

看到我更新的答案我添加了其他2個選項,你可以作爲變通 –

回答

2

所有對象GET「結合」,當該對象的容器是JIT編譯,通常的功能將被JIT編譯它執行的第一次。

當您將GetDebuggingInfo移入AddDebuggingInfo時,如果實際輸入AddDebuggingInfo方法,則只會嘗試對GetDebuggingInfo進行綁定並失敗。

另一個解決方法是,你可以推遲甚至更晚的結合,如果你聲明變量dynamic

#if DEBUG 
    dynamic tmpFoo = foo; 
    if (foo.GetType().GetMethod("GetDebuggingInfo", BindingFlags.Instance | BindingFlags.Public) != null) 
     messageBuilder.AppendLine(tmpFoo.GetDebuggingInfo()); 
#endif 

動態導致綁定在函數的調用點而不是在包含函數的enterence發生。

另一種選擇是隻使用MethodInfo你檢查空調用。

#if DEBUG 
    var info = foo.GetType().GetMethod("GetDebuggingInfo", BindingFlags.Instance | BindingFlags.Public); 
    if (info != null) 
    { 
     var text = (string)info.Invoke(foo, null); 
     messageBuilder.AppendLine(text); 
    } 
#endif 
0

看看在[ConditionalAttribute]

它做你的#if .... #endif代碼做什麼,但它也消除了裝飾方法的調用。

一個限制:裝飾方法必須返回void。所以,你最終會通過StringBuilder作爲參數。

將ConditionalAttribute應用於方法向編譯器指示編譯器不應將對該方法的調用編譯爲Microsoft中間語言(MSIL),除非定義了與ConditionalAttribute關聯的條件編譯符號。如果將此屬性應用於不返回void的方法,您將在Visual Studio中收到編譯錯誤。

static void Main() 
{  
    var sb = new StringBuilder();   
    Console.WriteLine("Calling AppendDebugInfo1"); 
    AppendDebugInfo1(sb); 
    Console.WriteLine("Calling AppendDebugInfo2"); 
    AppendDebugInfo2(sb); 
    Console.WriteLine(sb); 
} 

[Conditional("DEBUG")] 
public static void AppendDebugInfo1(StringBuilder sb) 
{ 
    sb.AppendLine("DEBUG is defined"); 
} 

[Conditional("DEBUG"), Conditional("SUPERDEBUG"))] 
public static void AppendDebugInfo2(StringBuilder sb) 
{ 
    sb.AppendLine("DEBUG or SUPERDEBUG is defined! whoaaaaa!"); 
} 
+0

我當然可以使用'ConditionalAttribute'我'AddDebuggingInfo'方法使用,但使用它不會解決我的根本問題。 1)我的測試DLL用於對被測DLL的所有以前發佈的版本 - 因爲測試DLL的調試和測試中的DLL是RELEASE將在發展失敗。 2)我的測試DLL是C++正在通過託管C++包裝 –

+0

我使用'ConditionalAttribute'但是我不能使用它試圖訪問,作爲建設在釋放模式即使在編譯器仍然要解決函數調用調試信息功能在其他DLL。 –