11

ClickOnceをデプロイしたアプリケーションで.NET2.0SP2に依存しています(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なしの.NET2.0で実行される場合、catchのコードは実行されません。AppDomain.CurrentDomain.UnhandledException例外は、イベントハンドラによってのみキャッチされます。

MissingMethodExceptionがキャッチされない可能性はどのようにありますか?これは特殊なケースであると想像できます。CLRは存在しないメソッドにヒットし、どういうわけかこれをcatchブロックに渡すことができません。その背後にある原理を理解したいと思います。

誰かがこの問題に関するリソースを持っていますか?キャッチブロックでキャッチできない他の例外はありますか?

4

4 に答える 4

15

メソッドが正しく入力される前、つまりキャッチブロックがヒットする前のJIT時に発生しているのではないかと思います。呼び出し元のメソッドをキャッチすると、それが整理される可能性があります...特に。で装飾する場合はそうです。それでもかなり危険なように聞こえます。MissingMethodExceptionCheckDotNet2SPMethodImpl[MethodImplOptions.NoInlining]

ただし、メソッドを呼び出そうとするのではなく、リフレクションを使用してメソッドの存在をいつでも確認できます。

于 2010-08-23T10:18:54.140 に答える
13

「回復不能」と定義されているいくつかの例外があります。そのうちの1つはMissingMethodException、メソッドがクラスにない場合、これは重大なエラーであり、クラスをアンロードし、回復するために新しいクラスをリロードする必要があるためです。

リカバリするには、再インストールし、アセンブリのバージョンを確認し、PEイメージが有効かどうかを確認する必要があります。

SP2がインストールされているかどうかだけを知りたい場合、デフォルトの方法は、インストールされているバージョンをチェックするだけのブートストラップアプリケーションを使用することです。問題がなければアプリケーションを実行し、そうでない場合は素晴らしいメッセージを表示します。


OPによって要求された更新:
キャッチが難しいかキャッチできないその他の例外(.NETのバージョンによって異なる場合があります。つまり、.NET 4.0でキャッチできないものが追加されます):(OutOfMemoryException同期時にキャッチできる)、StackOverflowException(キャッチできない)、(ThreadAbortExceptionキャッチできますが、キャッチブロックの最後で自動的に再レイズされるため特別です)、例外をスローするアセンブリでキャッチしようとすると(動的にロードする場合は、次のようになります)。を使用すると、それをキャッチすることができます)。また、一般に、から継承しない例外はキャッチするのが困難です(ただし、一般的なtry / catchブロックを使用してキャッチできます)。BadImageFormatExceptionMissingManifestResourceExceptionMissingMethodExceptionException

他にもありますが、上記の最初の3つは、実際に最も頻繁に遭遇するものです。

于 2010-08-23T10:19:22.220 に答える
4

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);
    }
于 2010-08-23T10:19:30.223 に答える
3

リフレクションを使用して、メソッドが存在するかどうかを確認できます。

private void CheckDotNet2SP()
{
    return typeof(WaitHandle).GetMethod("WaitOne", new Type[] { typeof(int) }) 
       != null;
} 
于 2010-08-23T10:27:56.713 に答える