Почему невозможно перехватить MissingMethodException?

У меня есть зависимость от .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?

11
задан Marek 23 August 2010 в 10:13
поделиться

4 ответа

Я подозреваю, что это происходит во время JIT, еще до того, как метод будет правильно введен, то есть до того, как ваш блок catch будет поражен. Возможно , что если вы поймаете MissingMethodException в вызывающем методе , это решит проблему ... особенно если вы украсите CheckDotNet2SP с помощью MethodImpl [MethodImplOptions.NoInlining] . Хотя это все еще звучит так, как будто это было бы довольно рискованно.

Вы всегда можете проверить наличие метода с помощью отражения, а не пытаться вызвать его.

14
ответ дан 3 December 2019 в 02:29
поделиться

Есть несколько исключений, которые определены как "неустранимые". Одним из них является MissingMethodException , потому что, если метод отсутствует в классе, это серьезная ошибка и требует выгрузки класса и перезагрузки нового класса для восстановления, что не может быть выполнено тривиально (если вообще ).

Для восстановления вам необходимо переустановить, проверить версии сборок, проверить, действительны ли образы PE и т. Д.

Если все, что вам нужно знать, это установлен ли SP2, по умолчанию используется приложение начальной загрузки. который просто проверяет установленную версию. Если все в порядке, он запускает приложение, если нет, показывает приятное сообщение.


Обновление, запрошенное OP:
Другие исключения, которые либо трудно поймать, либо не уловить (могут зависеть от вашей версии .NET, например .NET 4.0 добавлено больше неуловимых объектов): OutOfMemoryException (может быть обнаружено, когда оно синхронно), StackOverflowException (не может быть обнаружено), ThreadAbortException (может быть обнаружено, но является особенным, потому что оно будет автоматически повторно поднято в конце блока catch), BadImageFormatException и MissingManifestResourceException , если вы попытаетесь перехватить его в сборке, генерирующей исключение (если вы загружать его динамически, как и в случае с MissingMethodException , вы можете его перехватить). И вообще, любое исключение, которое не наследуется от Exception , трудно поймать (но вы можете поймать их с помощью общего блока try / catch).

Есть и другие, но с первыми тремя из вышеперечисленных вы чаще всего сталкиваетесь на практике.

12
ответ дан 3 December 2019 в 02:29
поделиться

Исключение выбрасывается на этапе 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 December 2019 в 02:29
поделиться

Вы можете использовать отражение, чтобы увидеть, существует ли метод.

private void CheckDotNet2SP()
{
    return typeof(WaitHandle).GetMethod("WaitOne", new Type[] { typeof(int) }) 
       != null;
} 
3
ответ дан 3 December 2019 в 02:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: