.NET 4.0裡異常處理的新機制

來源:互聯網
上載者:User

標籤:blog   http   使用   os   io   strong   檔案   資料   

本文轉載自donjuan

前幾天,有一個朋友問我為什麼在.NET裡不能捕捉(catch)到一些異常了,而且在調試器裡也捕捉不到。研究了一下,是.NET 4.0裡新的異常處理機制搗的鬼。

 

在.NET 4.0之後,CLR將會區別出一些異常(都是SEH異常),將這些異常標識為破壞性異常(Corrupted State Exception)。針對這些異常,CLR的catch塊不會捕捉這些異常,即使你用類似下面的代碼:

            try
            {
                TestMethod();
            }
            catch (Exception e)
            {
                Console.WriteLine("Catching exception: {0}", e);
            }

也沒有辦法捕捉到這些異常。之所以要這樣設計,在MSDN的文章Handling Corrupted State Exceptions裡已經提到了。即,有一些支援外掛程式的程式,例如Visual Studio或者SQL Server,它們支援調用Managed 程式碼編寫成的外掛程式,但是它們自己本身有很多代碼是由非託管的C++寫成的。由於外掛程式經常會調用到非託管的API,而很多時間,這些外掛程式的代碼根本就不知道如何處理非託管的API拋出來的SEH異常。在4.0以前,因為SEH異常被轉換成了跟普通.NET異常相同的異常,這樣程式員只要用catch ( Exception e)的模式就可以捕捉到所有的異常。這樣處理的問題是,由於SEH異常通常都不是Managed 程式碼拋出的,Managed 程式碼根本就不知道SEH異常被扔出來的原因,簡單的catch ( Exception e)處理使得整個程式會處於一個非常不穩定的狀態,使得前面被忽略的問題在後面以更嚴重的方式出現 — 例如儲存被破壞的資料。這樣,看起來使用catch ( Exception e)處理所有的異常的方法很簡單,但實際上讓程式員或者使用者在問題延後發生時,分析起來需要花費更多的精力。

 

因此在4.0以後,大部分SEH(我懷疑是所有)異常都被標識成破壞性異常,在.NET裡,預設情況下CLR不會捕捉它們,而是任由作業系統來處理—即關閉程式,並開啟一個錯誤對話方塊通知使用者。為了保證相容性,在4.0以前編譯的程式,例如在2.0、3.0和3.5編譯的程式,依然採用的是老的策略—即.NET會同時捕捉.NET異常和SEH異常。而在4.0下面編譯的程式才會使用新的策略,這也是在文章的開頭,我的朋友所碰到的問題。你可以在.NET 4.0下面編譯下面的程式,體驗一下這個新變化:

Program.cs:

using System;
using System.Runtime.InteropServices;
 
namespace ConsoleApplication1
{
    class Program
    {
        [DllImport("Ref.dll")]
        private extern static void TestMethod();
 
        static void Main(string[] args)
        {
            try
            {
                TestMethod();
            }
            catch (Exception e)
            {
                Console.WriteLine("Catching exception: {0}", e);
            }
        }
    }
}

 

 

Ref.cpp:

#include "stdafx.h"
 
extern "C" __declspec(dllexport) void TestMethod()
{
       int *p = NULL;
      
       // 會導致.NET拋出一個AccessViolation異常
       *p = 10;
}

 

上面的代碼裡,Program.cs使用P/Invoke技術調用了Ref.dll檔案裡的TestMethod,但是TestMethod嘗試給一個null 指標賦值,導致一個AccessViolation異常。如果你在2.0下面編譯program.cs,並執行的話,這個AccessViolation異常會被catch(Exception e)捕捉到,而如果你在4.0下面編譯並執行的話,你會發現catch (Exception e)是不能捕捉到這個異常的。

 

然而並不是所有人都想要這個新的異常機制,如果你的程式是在4.0下面編譯並運行,而你又想在.NET程式裡捕捉到SEH異常的話,有兩個方案可以嘗試:

1.         在託管程式的.config檔案裡,啟用legacyCorruptedStateExceptionsPolicy這個屬性,即簡化的.config檔案類似下面的檔案:

 

App.config:

<?xml version="1.0"?>
<configuration>
 <startup>
   <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
 </startup>
    <runtime>
      <legacyCorruptedStateExceptionsPolicy enabled="true" />
    </runtime>
</configuration>

 

這個設定告訴CLR 4.0,整個.NET程式都要使用老的異常捕捉機制。

 

2.         在需要捕捉破壞性異常的函數外面加一個HandleProcessCorruptedStateExceptions屬性,這個屬性只控制一個函數,對託管程式的其他函數沒有影響,例如:

[HandleProcessCorruptedStateExceptions]
static void Main(string[] args)
{
    try
    {
        TestMethod();
    }
    catch (Exception e)
    {
        Console.WriteLine("Catching exception: {0}", e);
    }
}

 

你也可以下載範例程式碼自己試一下(需要VS 2010才能編譯):

/Files/killmyday/CSEsample.zip

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.