解決異常:公共語言執行時檢測到無效的程式

zhuweisky發表於2014-10-23

  我碰到這個問題比較奇怪,我寫的一個方法(基於.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。

  好吧,現在問題總算是解決了,好好折騰了一番啊~~

 

 

相關文章