你能在C#代码中捕获本机异常吗?

时间:2008-09-29 20:41:18

标签: c# .net exception

在C#代码中,您是否可以捕获从某些非托管库中深入抛出的本机异常?如果是这样,你需要做任何不同的事情才能抓住它或做一个标准的尝试......抓住它吗?

8 个答案:

答案 0 :(得分:31)

您可以使用Win32Exception并使用其NativeErrorCode属性来适当地处理它。

// http://support.microsoft.com/kb/186550
const int ERROR_FILE_NOT_FOUND = 2;
const int ERROR_ACCESS_DENIED = 5;
const int ERROR_NO_APP_ASSOCIATED = 1155; 

void OpenFile(string filePath)
{
    Process process = new Process();

    try
    {
        // Calls native application registered for the file type
        // This may throw native exception
        process.StartInfo.FileName = filePath;
        process.StartInfo.Verb = "Open";
        process.StartInfo.CreateNoWindow = true;
        process.Start();
    }
    catch (Win32Exception e)
    {
        if (e.NativeErrorCode == ERROR_FILE_NOT_FOUND || 
            e.NativeErrorCode == ERROR_ACCESS_DENIED ||
            e.NativeErrorCode == ERROR_NO_APP_ASSOCIATED)
        {
            MessageBox.Show(this, e.Message, "Error", 
                    MessageBoxButtons.OK, 
                    MessageBoxIcon.Exclamation);
        }
    }
}

答案 1 :(得分:16)

Catch without()将捕获非CLS兼容的异常,包括本机异常。

try
{

}
catch
{

}

有关详细信息,请参阅以下FxCop规则 http://msdn.microsoft.com/en-gb/bb264489.aspx

答案 2 :(得分:11)

C#和本机代码之间的互操作层将异常转换为托管表单,允许它被C#代码捕获。从.NET 2.0开始,catch (Exception)应该捕获除了不可恢复的错误以外的任何内容。

答案 3 :(得分:5)

使用.NET Reflector的地方我看过以下代码:

try {
  ...
} catch(Exception e) {
  ...
} catch {
  ...
}

嗯,C#不允许抛出异常而不是从System.Exception类派生。据我所知,interop marshaller的任何异常包都由继承System.Exception的异常类包装。

所以我的问题是是否可以捕获不是System.Exception的异常。

答案 4 :(得分:5)

这取决于您所谈论的本机异常类型。如果你指的是SEH例外,那么CLR会做两件事之一。

  1. 如果是已知的SEH错误代码,它会将其映射到相应的.Net异常(即OutOfMemoryException)
  2. 如果是不可映射(E_FAIL)或未知代码,它只会抛出一个SEHException实例。
  3. 这两个都将被一个简单的“catch(Exception)”块捕获。

    可以跨越本机/托管边界的其他类型的本机异常是C ++异常。我不确定它们是如何映射/处理的。我的猜测是,由于Windows在SEH之上实现了C ++异常,因此它们只是以相同的方式映射。

答案 5 :(得分:3)

几乎,但不完全。您将使用

捕获异常
try 
{
  ...
}
catch (Exception e)
{
  ...
}

但你仍然有潜在的问题。根据{{​​3}},为了确保调用异常析构函数,你必须注意:

try
{
  ...
}
catch
{
  ...
}

这是确保调用异常析构函数的唯一方法(虽然我不确定为什么)。但是,这会让你对蛮力与可能的内存泄漏进行权衡。

顺便说一句,如果您使用(例外e)方法,您应该知道可能遇到的不同类型的例外。 RuntimeWrappedException是任何托管的非异常类型将被映射到的(对于可以抛出字符串的语言),而其他类型将被映射,例如OutOfMemoryException和AccessViolationException。 COM Interop HRESULTS或E___FAIL以外的异常将映射到COMException,最后在E_FAIL或任何其他未映射的异常的最后都有SEHException。

那你该怎么办?最好的选择是不要从你的非托管代码中抛出异常!哈。实际上,如果你有一个选择,设置障碍和失败使得选择哪个更糟,在异常处理期间内存泄漏的可能性,或者不知道你的异常是什么类型。

答案 6 :(得分:0)

如果您使用

try
{

}
catch(Exception ex)
{

}

它将捕获所有异常,具体取决于您如何调用外部库,您可能会获得一个封装错误的com相关异常,但它会捕获错误。

答案 7 :(得分:0)

标准尝试捕获应该做我相信的技巧。

我遇到一个类似的问题,一个System.data异常抛出一个未被捕获的sqlClient异常,在我的代码中添加了一个try..catch,在实例中做了诀窍