11

我在 ClickOnce 部署的应用程序中依赖于 .NET 2.0 SP2(该ApplicationDeployment.CurrentDeployment.CheckForDetailedUpdate(false)方法仅适用于 SP2)。

我想检查应用程序启动期间是否存在 SP2。我试图通过在调用仅限 SP2 的方法后捕获 MissingMethodException 来检测这一点。

    /// <summary>
    /// The SP2 bootstrapper does not allow HomeSite installation
    /// http://msdn.microsoft.com/en-us/vstudio/bb898654.aspx
    /// So we only advice the user to download .NET 2.0 SP2 manually.
    /// </summary>
    private void CheckDotNet2SP()
    {
        WaitHandle wh = new AutoResetEvent(true);
        try
        {
            wh.WaitOne(1); //this method is .NET 2.0 SP2 only
        }
        //NOTE: this catch does not catch the MissingMethodException
        catch (Exception) //change to catch(MissingMethodException) does not help
        {
            //report that .NET 2.0 SP2 is missing
        }
        finally
        {
            wh.Close();
        }
    }

在没有 SP2 的 .NET 2.0 上运行时,catch 中的代码永远不会执行。异常仅由AppDomain.CurrentDomain.UnhandledException事件处理程序捕获。

MissingMethodException 怎么可能没有被捕获?我可以想象这是一种特殊情况——CLR 遇到了一个不存在的方法,并且无法以某种方式将其传递给 catch 块。我想了解这背后的原理。

有人有关于这个问题的任何资源吗?是否还有其他无法在 catch 块中捕获的异常?

4

4 回答 4

15

我怀疑它发生在 JIT 时间,甚至在正确输入方法之前 - 即在你的 catch 块被命中之前。如果您在调用方法中捕获,则可能会对其进行排序……特别是如果您使用. 不过,这听起来仍然很冒险。MissingMethodExceptionCheckDotNet2SPMethodImpl[MethodImplOptions.NoInlining]

您总是可以通过反射检查方法的存在,而不是尝试调用它。

于 2010-08-23T10:18:54.140 回答
13

有一些例外被定义为“不可恢复”。其中之一是MissingMethodException,因为如果一个类中缺少一个方法,这是一个严重的错误,它需要卸载该类并重新加载一个新类来恢复,这不能轻易完成(如果有的话)。

要恢复,您需要重新安装、检查程序集的版本、检查 PE 映像是否有效等。

如果您只想知道是否安装了 SP2,则默认方法是使用引导应用程序,它只检查已安装的版本。如果一切正常,它会运行应用程序,如果不是,它会显示一条好消息。


OP 要求的更新:
其他难以捕获或无法捕获的异常(可能取决于您的 .NET 版本,即 .NET 4.0 添加了更多无法捕获的内容):(OutOfMemoryException可以在同步时捕获),StackOverflowException(永远无法捕获) ),ThreadAbortException(可以被捕获,但很特殊,因为它会在捕获块的末尾自动重新引发),BadImageFormatException并且MissingManifestResourceException如果您尝试在抛出异常的程序集中捕获它(如果您动态加载它,与,MissingMethodException你有能力抓住它)。通常,任何不继承自的异常Exception都很难捕获(但您可以使用通用的 try/catch 块捕获它们)。

还有其他的,但上面的前三个是您在实践中最常遇到的。

于 2010-08-23T10:19:22.220 回答
4

JIT 编译步骤抛出异常,因此您没有进入方法。试试这个版本:

    private bool CheckDotNet2SP()
    {
        try
        {
            CheckImpl();
            return true;
        }
        catch (MissingMethodException)
        {
            return false;
        }
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private void CheckImpl()
    {
        using (var wh = new ManualResetEvent(true))
            wh.WaitOne(1);
    }
于 2010-08-23T10:19:30.223 回答
3

您可以使用反射来查看该方法是否存在。

private void CheckDotNet2SP()
{
    return typeof(WaitHandle).GetMethod("WaitOne", new Type[] { typeof(int) }) 
       != null;
} 
于 2010-08-23T10:27:56.713 回答