[英]Why is it not possible to catch 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块中捕获?
我怀疑它发生在JIT时间,在方法正确输入之前 - 即在你的catch块被击中之前。 如果你在调用方法中捕获MissingMethodException
,那么它可能会将其排序...特别是如果你使用MethodImpl[MethodImplOptions.NoInlining]
装饰CheckDotNet2SP
。 它听起来仍然很冒险。
你总是可以通过反射来检查方法的存在,而不是通过尝试调用它。
有一些例外被定义为“不可恢复”。 其中一个是MissingMethodException
,因为如果一个类中缺少一个方法,这是一个严重的错误,它需要卸载类并重新加载一个新类来恢复,这是不可能完成的(如果有的话)。
要恢复,您需要重新安装,检查程序集的版本,检查PE映像是否有效等。
如果您只想知道是否安装了SP2,则默认方法是使用引导应用程序,该应用程序只检查已安装的版本。 如果一切正常,它运行应用程序,如果没有它显示一个很好的消息。
OP要求的更新:
其他难以捕获或无法捕获的异常(可能取决于您的.NET版本,即.NET 4.0增加了更多无法捕获): OutOfMemoryException
(可以在同步时捕获), StackOverflowException
(永远不能捕获), ThreadAbortException
(可以捕获,但是很特殊,因为它会在catch块的末尾自动重新加载), BadImageFormatException
和MissingManifestResourceException
如果你试图在抛出异常的程序集中捕获它(如果你动态加载它,就像使用MissingMethodException
,您可以捕获它)。 通常,任何不从Exception
继承的Exception
都很难捕获(但是您可以使用通用的try / catch块捕获它们)。
还有其他一些,但前面的三个是你在实践中经常遇到的。
在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);
}
您可以使用反射来查看方法是否存在。
private void CheckDotNet2SP()
{
return typeof(WaitHandle).GetMethod("WaitOne", new Type[] { typeof(int) })
!= null;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.