我们可以在C#代码中捕获本地异常吗?

时间:2020-03-06 14:53:44  来源:igfitidea点击:

在Ccode中,我们可以捕获某个非托管库中从深处抛出的本机异常吗?如果是这样,我们需要采取其他措施来捕获它还是使用标准try ... catch来获取它?

解决方案

如果我们使用

try
{

}
catch(Exception ex)
{

}

它会捕获所有异常,具体取决于我们如何调用外部库,我们可能会获得与com相关的异常,该异常封装了错误,但可以捕获该错误。

Cand本机代码之间的互操作层会将异常转换为托管形式,从而使其可以被Ccode捕获。从.NET 2.0开始,catch(Exception)应该捕获除不可恢复的错误以外的任何内容。

我相信,标准的尝试捕获应该可以解决问题。

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

我们可以使用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);
        }
    }
}

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

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

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

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

不带()的捕获将捕获不符合CLS要求的异常,包括本机异常。

try
{

}
catch
{

}

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

这取决于我们正在谈论的本机异常类型。如果我们指的是SEH异常,则CLR将执行以下两项操作之一。

  • 如果是已知的SEH错误代码,它将把它映射到适当的.Net异常(即OutOfMemoryException)
  • 在不可映射(E_FAIL)或者未知代码的情况下,它将仅引发SEHException实例。

这两个都将通过一个简单的" catch(Exception)"块来捕获。

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

差不多,但是不完全是。我们将通过捕获异常

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

但是我们仍然会遇到潜在的问题。根据MSDN,为了确保调用异常析构函数,我们必须像这样捕获:

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

这是确保调用异常析构函数的唯一方法(尽管我不确定为什么)。但是,这需要在蛮力与可能的内存泄漏之间进行权衡。

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

那你该怎么办?最好的选择是不要在非托管代码中抛出异常!哈哈确实,尽管我们可以选择,但会设置障碍并导致失败的选择更加糟糕,在异常处理过程中可能会发生内存泄漏,或者不知道异常是什么类型。