2010-07-27 4 views
2

Je suis en train de recréer un TypeLoadException à des fins de démonstration, j'ai donc une configuration de bibliothèque ridiculement loufoque qui ressemble à ceci:TypeLoadException ne se coince pas try/catch

TestProject --> TheLibrary [1.0] 
      \-> ProxyForV2 -> TheLibrary [2.0] 

TheLibrary version 1 a ces pertinentes interfaces:

public interface IConsistentThing 
{ 
    int ConsistentProperty { get; set; } 
} 

public interface IShrinkingThing 
{ 
    int RemovedProperty { get; set; } 
} 

Alors que la version 2 des interfaces de TheLibrary ressemblent:

public interface IConsistentThing 
{ 
    int ConsistentProperty { get; set; } 
} 

public interface IShrinkingThing 
{ } 

ProxyForV2 a cette classe qui implémente la version 2.0 IShrinkingThing:

public class ShrinkingThingImpl : IShrinkingThing 
{ 
    public int ConsistentProperty { get; set; } 
} 

Ainsi, TestProject, je comptais faire un TypeLoadException si quelqu'un essaie d'attribuer une ProxyForV2.ShrinkingThingImpl, depuis la première version de l'interface a un propriété qui n'est pas implémentée par la deuxième version. Pour le prouver, j'ai un test unitaire qui ressemble à:

[TestMethod] 
public void ShrinkingThingBreaks() 
{ 
    try 
    { 
     IShrinkingThing thing = new ProxyForV2.ShrinkingThingImpl(); 

     Assert.Fail("This should have caused a TypeLoadException"); 
    } 
    catch (TypeLoadException) 
    { 
     // valid 
    } 
} 

Voici mon problème: ce test échoue. Mais pas en raison de mon Assert.Fail, comme je m'y attendais. La sortie de test ressemble à ceci:

Méthode d'essai TestProject.LoadTester.ShrinkingThingBreaks jeté exception: System.TypeLoadException: méthode 'get_RemovedProperty' dans le type 'ProxyForV2.ShrinkingThingImpl' de l'assemblage « ProxyForV2, Version = 1.0.0.0, Culture = neutre, PublicKeyToken = null » n'a pas une implémentation ..

Ainsi, un TypeLoadException est en cours et bien que la jetée seul endroit où il pouvait peut- être jeté est dans un bloc try avec un catch (TypeLoadException), l'exception refuse être attrapé. Au-delà, même si j'utilise un fourre-tout, le test unitaire échoue avec la même erreur que précédemment:

[TestMethod] 
public void ShrinkingThingBreaks() 
{ 
    try 
    { 
     IShrinkingThing thing = new ProxyForV2.ShrinkingThingImpl(); 

     Assert.Fail("This should have caused a TypeLoadException"); 
    } 
    catch 
    { 
     // valid 
    } 
} 

Que se passe-t-il? Évidemment, c'est un scénario complètement artificiel, mais j'aimerais quand même savoir ce qui se passe afin que cette erreur puisse être évitée au moment de l'exécution ou au moins traitée si cela se produit (oui, je suis conscient que la solution ultime est de assurez-vous que toutes les versions de votre bibliothèque sont les mêmes).

Le pire est que tout accès à la classe du tout, comme typeof(ProxyForV2.ConsistentThingImpl) ou ProxyForV2.ConsistentThingImpl.SomeStaticFunction() les causes de cette non saisissable TypeLoadException, il est donc clair que le problème trouve son origine lorsque .NET tente de charger la classe du tout, pas de toute cession. Ma seule idée pour atténuer ce problème est d'essayer de charger le type dans un domaine d'application différent afin qu'il n'interfère pas et ensuite faire des trucs de réflexion fous pour voir si l'interface est compatible avec l'implémentation, mais cela semble comme une overkill complète et totale. En résumé: Pourquoi semble-t-il impossible d'attraper ce problème de façon «normale» et comment puis-je résoudre des problèmes comme celui-ci lors de l'exécution?

+1

Pas tout à fait sûr sur celui-ci, donc seulement commentant ... Les types pour un test unitaire ne sont-ils pas tous chargés à l'avant? L'exception TypeLoadException est donc lancée avant même que vous n'ayez accédé à votre bloc try/catch. Je ne sais pas comment vous pourriez tester cela ... – Jaymz

+0

Il y a d'autres tests unitaires dans la classe qui passent parfaitement bien. Si vous voulez dire que les types utilisés dans les méthodes sont chargés à l'appel de la méthode, cela peut être la racine du problème. –

Répondre

5

Les types sont chargés avant que l'exécution ne commence sur la méthode qui les utilise.Pour ce faire, vous devez:

[TestMethod] 
public void ShrinkingThingBreaks() 
{ 
    try 
    { 
     InnerShrinkingThingBreaks(); 

     Assert.Fail("This should have caused a TypeLoadException"); 
    } 
    catch 
    { 
     // valid 
    } 
} 

[MethodImpl(MethodImplAttributes.NoInlining)] 
private void InnerShrinkingThingBreaks() 
{ 
     IShrinkingThing thing = new ProxyForV2.ShrinkingThingImpl(); 
} 
+1

Fonctionne. Il fonctionne également en faisant la même chose avec une fonction lambda. –

+0

@TravisGockel un échantillon avec la fonction lamda? – Kiquenet

+0

@Kiquenet: Comme cela fait 4 ans, je ne me souviens pas exactement, mais je pense que dans le bloc 'try', j'ai dit quelque chose comme:' Action f = delegate() {var x = nouveau ProxyForV2.ShrinkingThingImpl() ; } f(); ' –