我碰到這個問題比較奇怪,我寫的一個方法(基於.NET 2.0)在win7、win2003下執行沒有問題,在winxp下執行就拋異常:“公共語言執行時檢測到無效的程式”,對應英文為:common language runtime detected an invalid program.
拋異常的方法程式碼摘抄如下:
private Control control = ...; public void ActionOnUI<T1>(bool showMessageBoxOnException, bool beginInvoke, CbGeneric<T1> method, params object[] args) { if (this.control.InvokeRequired) { if (beginInvoke) { this.control.BeginInvoke(new CbGeneric<bool, bool, CbGeneric<T1>, object[]>(this.ActionOnUI), showMessageBoxOnException, beginInvoke, method, args); } else { this.control.Invoke(new CbGeneric<bool, bool, CbGeneric<T1>, object[]>(this.ActionOnUI), showMessageBoxOnException, beginInvoke, method, args); } } else { try { method((T1)args[0]); } catch (Exception ee) { if (showMessageBoxOnException) { MessageBox.Show(ee.Message); } } } }
方法的目的是對UI呼叫轉發做一個封裝,讓使用者更方便的將呼叫轉發到UI執行緒。
但是,這個方法在執行時,異常在xp下發生了:
Common Language Runtime detected an invalid program.
at ESBasic.Helpers.UiSafeInvoker.ActionOnUI[T1](Boolean showMessageBoxOnException, Boolean beginInvoke, CbGeneric`1 method, Object[] args)
我在網上搜了一些相關問題的解答,比較靠譜的一點是這樣說的:
“這種錯誤非常少見,是一個編譯器錯誤,通常產生在將C#等託管語言生成為MSIL時候出的錯,沒有什麼好的解決辦法,現在可行的方法好像就是修改現在的程式結構,這樣根據新的結構生成新的MSIL時不會出錯就基本可以避免這個問題。”
根據這個提示,我對方法的程式碼進行了各種修改嘗試,最後終於得到了一種在xp下也不拋異常的結構,貼上如下:
private Control control = ...; public void ActionOnUI<T1>(bool showMessageBoxOnException, bool beginInvoke, CbGeneric<T1> method, T1 args) { if (this.control.InvokeRequired) { if (beginInvoke) { this.control.BeginInvoke(new CbGeneric<bool, CbGeneric<T1>, T1>(this.Do_ActionOnUI<T1>), showMessageBoxOnException, method, args); return; } this.control.Invoke(new CbGeneric<bool, CbGeneric<T1>, T1>(this.Do_ActionOnUI<T1>), showMessageBoxOnException, method, args); return; } this.Do_ActionOnUI<T1>(showMessageBoxOnException, method, args); } private void Do_ActionOnUI<T1>(bool showMessageBoxOnException, CbGeneric<T1> method, T1 args) { try { method(args); } catch (Exception ee) { if (showMessageBoxOnException) { MessageBox.Show(ee.Message); } } }
總結起來,改變的幾點如下:
(1)將真正執行的部分重構為一個方法Do_ActionOnUI,然後,轉發呼叫Invoke都指向這個方法。
(2)Invoke轉發呼叫時,為指向的方法加上泛型引數,避免編譯器自動去匹配。
(3)將弱型別的引數object[]修改為強型別的引數T1。
好吧,現在問題總算是解決了,好好折騰了一番啊~~