2010-08-23 3 views
10

J'ai une dépendance sur .NET 2.0 SP2 dans mon application déployée ClickOnce (la méthode ApplicationDeployment.CurrentDeployment.CheckForDetailedUpdate(false) est SP2 uniquement).Pourquoi est-il impossible d'attraper MissingMethodException?

Je voudrais vérifier si SP2 est présent lors du démarrage de l'application. J'ai essayé de détecter ceci en attrapant MissingMethodException après avoir appelé une méthode 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(); 
     } 
    } 

Le code dans catch ne s'exécute jamais lorsque cela s'exécute sur .NET 2.0 sans SP2. L'exception est interceptée uniquement par le gestionnaire d'événements AppDomain.CurrentDomain.UnhandledException.

Comment est-il possible que MissingMethodException ne soit pas interceptée? Je peux imaginer que c'est un cas particulier - le CLR frappe une méthode qui n'existe pas et d'une manière ou d'une autre il n'est pas possible de passer cela au bloc catch. Je voudrais comprendre le principe derrière cela.

Quelqu'un a des ressources sur ce problème? Existe-t-il d'autres exceptions qui ne peuvent pas être interceptées dans un bloc catch?

Répondre

13

Je suppose que cela se passe au moment JIT, avant même que la méthode soit correctement entrée, c'est-à-dire avant que votre bloc catch ne soit touché. C'est possible que si vous attrapez MissingMethodException dans la méthode appelant, cela va le trier ... particulièrement si vous décorez CheckDotNet2SP avec MethodImpl[MethodImplOptions.NoInlining]. Il semble toujours que ce serait très risqué cependant.

Vous pouvez toujours vérifier la présence de la méthode avec réflexion plutôt que d'essayer de l'appeler.

10

Il existe quelques exceptions qui ont été définies comme "irrécupérables". L'un d'entre eux est MissingMethodException, car si une méthode est manquante dans une classe, il s'agit d'une erreur grave et cela nécessite de décharger la classe et de recharger une nouvelle classe à récupérer, ce qui ne peut pas être fait trivialement (voire pas du tout).

Pour récupérer, vous devez réinstaller, vérifier les versions des assemblées, vérifier si les images de PE sont valables etc.

Si tout ce que vous voulez savoir est de savoir si le Service Pack 2 est installé, la méthode par défaut utilise un application bootstrap qui vérifie simplement la version installée. Si tout va bien, il lance l'application, sinon il montre un bon message.


mise à jour demandée par OP:
D'autres exceptions qui sont soit difficiles à attraper ou uncatchable (peut dépendre de votre version de .NET, à savoir, 4.0 .NET ajouté plus uncatchables): OutOfMemoryException (peut être attrapé quand il est synchrone), StackOverflowException (ne peut jamais être attrapé), ThreadAbortException (peut être attrapé, mais est spécial car il sera automatiquement sur-relancé à la fin de la capture-bloc), BadImageFormatException et MissingManifestResourceException si vous essayez d'attraper dans l'assemblage lançant l'exception (si vous le chargez dynamiquement, comme avec MissingMethodException, vous êtes capable de l'attraper). Et en général, toute exception qui n'hérite pas de Exception est difficile à attraper (mais vous pouvez les attraper avec un bloc try/catch générique).

Il y en a d'autres, mais les trois premiers sont ceux que vous rencontrerez le plus souvent en pratique.

+0

pouvez-vous s'il vous plaît énumérer d'autres types d'exception 'irrécupérable'? – Marek

+0

@Marek: fait, j'ai mis à jour la réponse. – Abel

+1

Avez-vous une référence pour ces exceptions "irrécupérables"? Je vois qu'il est référencé dans [Application.DispatcherUnhandledException] (http://msdn.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception%28v=vs.85%29.aspx), mais je ne trouve pas d'informations définitives. –

3

Une exception est générée lors de la compilation JIT, vous n'avez donc pas utilisé la méthode. Essayez cette version:

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

Afaict, cette méthode va quand même décharger l'application en cas d'erreur car elle est considérée comme irrécupérable. – Abel

3

Vous pouvez utiliser la réflexion pour voir si la méthode existe.

private void CheckDotNet2SP() 
{ 
    return typeof(WaitHandle).GetMethod("WaitOne", new Type[] { typeof(int) }) 
     != null; 
} 
+0

Notez que cela ne fonctionnera pas si l'exception est réellement lancée par le compilateur JIT. Cela ne fonctionnera que lorsque l'appel à la méthode est lui-même fait par réflexion. – Abel

Questions connexes