为什么无法捕获MissingMethodException?

时间:2010-08-23 10:13:24

标签: c# .net .net-2.0 clr missingmethodexception

我在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 个答案:

答案 0 :(得分:14)

我怀疑它发生在JIT时间,在方法正确输入之前 - 即在你的catch块被击中之前。 可能如果你在调用方法中捕获MissingMethodException,那就会将其排序......特别是如果你用{{CheckDotNet2SP装饰MethodImpl[MethodImplOptions.NoInlining] 1}}。它听起来仍然很冒险。

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

答案 1 :(得分:11)

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

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

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


OP要求的更新:
其他难以捕获或无法捕获的异常(可能取决于您的.NET版本,即.NET 4.0添加了更多无法捕获):OutOfMemoryException(可以在同步时捕获),StackOverflowException (永远不会被捕获),ThreadAbortException(可以捕获,但是特殊因为它会在捕获块结束时自动重新加载),BadImageFormatExceptionMissingManifestResourceException如果你' d尝试在抛出异常的程序集中捕获它(如果你动态加载它,与MissingMethodException相同,你就能捕获它)。通常,任何不从Exception继承的异常都很难捕获(但是你可以使用通用的try / catch块来捕获它们。)

还有其他人,但前面三个是你在实践中经常遇到的那些。

答案 2 :(得分:3)

在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);
    }

答案 3 :(得分:3)

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

private void CheckDotNet2SP()
{
    return typeof(WaitHandle).GetMethod("WaitOne", new Type[] { typeof(int) }) 
       != null;
}