У меня есть зависимость от .NET 2.0 SP2 в моем развернутом приложении ClickOnce
(метод ApplicationDeployment.CurrentDeployment.CheckForDetailedUpdate (false)
является SP2 Только).
Я хотел бы проверить, присутствует ли SP2 при запуске приложения. Я попытался обнаружить это, перехватив MissingMethodException после вызова метода только для SP2.
/// <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();
}
}
Код в catch никогда не выполняется, если он выполняется на .NET 2.0 без SP2. Исключение перехватывается только обработчиком событий AppDomain.CurrentDomain.UnhandledException
.
Как это возможно, что MissingMethodException не обнаружен? Я могу представить, что это особый случай - CLR попадает в метод, которого не существует, и почему-то невозможно передать это в блок catch. Я хотел бы понять принцип, лежащий в основе этого.
У кого-нибудь есть ресурсы по этой проблеме? Существуют ли какие-либо другие исключения, которые не могут быть пойманы в блоке catch?
Я подозреваю, что это происходит во время JIT, еще до того, как метод будет правильно введен, то есть до того, как ваш блок catch будет поражен. Возможно , что если вы поймаете MissingMethodException
в вызывающем методе , это решит проблему ... особенно если вы украсите CheckDotNet2SP
с помощью MethodImpl [MethodImplOptions.NoInlining]
. Хотя это все еще звучит так, как будто это было бы довольно рискованно.
Вы всегда можете проверить наличие метода с помощью отражения, а не пытаться вызвать его.
Есть несколько исключений, которые определены как "неустранимые". Одним из них является MissingMethodException
, потому что, если метод отсутствует в классе, это серьезная ошибка и требует выгрузки класса и перезагрузки нового класса для восстановления, что не может быть выполнено тривиально (если вообще ).
Для восстановления вам необходимо переустановить, проверить версии сборок, проверить, действительны ли образы PE и т. Д.
Если все, что вам нужно знать, это установлен ли SP2, по умолчанию используется приложение начальной загрузки. который просто проверяет установленную версию. Если все в порядке, он запускает приложение, если нет, показывает приятное сообщение.
Обновление, запрошенное OP:
Другие исключения, которые либо трудно поймать, либо не уловить (могут зависеть от вашей версии .NET, например .NET 4.0 добавлено больше неуловимых объектов): OutOfMemoryException
(может быть обнаружено, когда оно синхронно), StackOverflowException
(не может быть обнаружено), ThreadAbortException
(может быть обнаружено, но является особенным, потому что оно будет автоматически повторно поднято в конце блока catch), BadImageFormatException
и MissingManifestResourceException
, если вы попытаетесь перехватить его в сборке, генерирующей исключение (если вы загружать его динамически, как и в случае с MissingMethodException
, вы можете его перехватить). И вообще, любое исключение, которое не наследуется от 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;
}