为什么无法捕获MissingMethodException?

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

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

  ///  /// 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. ///  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中的代码永远不会执行。 该exception仅由AppDomain.CurrentDomain.UnhandledException事件处理程序捕获。

怎么可能没有捕获到MissingMethodException? 我可以想象这是一个特殊情况 – CLR命中一个不存在的方法,不知怎的,它不可能将它传递给catch块。 我想了解这背后的原理。

任何人都有这方面的资源吗? 是否有任何其他exception无法在catch块中捕获?

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

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

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

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

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


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

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

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

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

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

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