Domanda

Ho una dipendenza da .NET 2.0 SP2 nel mio ClickOnce schierato applicazione (Il metodo ApplicationDeployment.CurrentDeployment.CheckForDetailedUpdate(false) è SP2 solo).

Vorrei verificare se SP2 è presente durante l'avvio dell'applicazione. Ho cercato di rilevare questo catturando MissingMethodException dopo la chiamata di un metodo SP2-only.

    /// <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();
        }
    }

Il codice nella cattura mai eseguito quando questo viene eseguito su .NET 2.0 senza SP2. L'eccezione e 'colto solo dal gestore di eventi AppDomain.CurrentDomain.UnhandledException.

Come è possibile che il MissingMethodException non viene catturato? Posso immaginare che questo è un caso speciale - il CLR colpisce un metodo che non esiste e in qualche modo non è possibile passare questo al blocco catch. Vorrei capire il principio alla base di questo.

Chiunque ha tutte le risorse su questo tema? Ci sono altre eccezioni che non possono essere catturati in un blocco catch?

È stato utile?

Soluzione

ho il sospetto che sta accadendo al momento JIT, prima che il metodo è ancora correttamente inserito - vale a dire prima che il blocco catch è successo. E ' possibile che se si cattura MissingMethodException nel chiamando il metodo , che ordinare fuori ... soprattutto se si decorano con CheckDotNet2SP MethodImpl[MethodImplOptions.NoInlining]. Suona ancora come sarebbe piuttosto rischioso però.

Si può sempre verificare la presenza del metodo con la riflessione, piuttosto che cercando di chiamarlo però.

Altri suggerimenti

Ci sono alcune eccezioni che sono stati definiti come "irrecuperabile". Uno di loro è MissingMethodException, perché se un metodo non è presente in una classe, questo è un errore grave e richiede lo scarico della classe e ricaricando una nuova classe per il recupero, che non può essere fatto banalmente (se non del tutto).

Per recuperare, è necessario reinstallare, controllare le versioni delle assemblee, controllare se le immagini di PE sono validi etc.

Se tutto quello che vogliamo sapere è se è installato SP2, il metodo di default utilizza un'applicazione di bootstrap che si limita a controlli la versione installata. Se tutto va bene, si esegue l'applicazione, se non mostra un messaggio di bello.


Aggiornamento richiesto da OP:
Altre eccezioni che sono o difficile da catturare o imprendibile (può dipendere la vostra versione di .NET, vale a dire, NET 4.0 aggiunto più uncatchables): OutOfMemoryException (possono essere catturati quando è sincrona), StackOverflowException (non può mai essere catturati), ThreadAbortException (possono essere catturati, ma è speciale perché sarà automaticamente rilanciato alla fine del catch-blocco), BadImageFormatException e MissingManifestResourceException se avresti cercato di prenderlo in assemblea gettare l'eccezione (se lo si carica in modo dinamico, proprio come con MissingMethodException, si è in grado di catturare esso). E, in generale, tutte le eccezioni che non eredita da Exception è difficile da catturare (ma è possibile catturare con una prova / blocco generico cattura).

Ci sono altri, ma i primi tre di cui sopra sono quelli che si incontrano più frequentemente nella pratica.

viene generata un'eccezione in fase di compilazione JIT, quindi non è stato un passo in metodo. Provate questa versione:

    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);
    }

Si potrebbe utilizzare la reflection per vedere se il metodo esiste.

private void CheckDotNet2SP()
{
    return typeof(WaitHandle).GetMethod("WaitOne", new Type[] { typeof(int) }) 
       != null;
} 
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top