Почему невозможно поймать MissingMethodException? - PullRequest
11 голосов
/ 23 августа 2010

У меня есть зависимость от .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 Я хотел бы понять принцип этого.

У кого-нибудь есть ресурсы по этому вопросу? Существуют ли другие исключения, которые не могут быть перехвачены в блоке перехвата?

Ответы [ 4 ]

14 голосов
/ 23 августа 2010

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

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

12 голосов
/ 23 августа 2010

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

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

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


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

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

3 голосов
/ 23 августа 2010

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

private void CheckDotNet2SP()
{
    return typeof(WaitHandle).GetMethod("WaitOne", new Type[] { typeof(int) }) 
       != null;
} 
3 голосов
/ 23 августа 2010

Исключение выдается на этапе компиляции 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);
    }
...