294 votes

TypeLoadException indique "pas d'implémentation", mais il est implémenté

J'ai un bug très bizarre sur notre machine de test. L'erreur est la suivante :

System.TypeLoadException: Method 'SetShort' in type 'DummyItem' from assembly 'ActiveViewers (...)' does not have an implementation.

Je ne comprends pas pourquoi. SetShort se trouve dans la DummyItem et j'ai même recompilé une version avec des écritures dans le journal des événements juste pour m'assurer qu'il ne s'agissait pas d'un problème de déploiement/version. Ce qui est étrange, c'est que le code appelant n'appelle même pas la classe SetShort méthode.

17 votes

J'aime la façon dont vous avez partagé votre expérience avec la communauté pour nous aider tous, et vous nous avez même encouragés à lire les autres réponses, merci. Malheureusement, aucune des suggestions n'a fonctionné pour moi. Vous voulez savoir ce qui a fonctionné pour moi ? Redémarrer Visual Studio. Pourquoi n'ai-je pas essayé d'abord ?

0 votes

Merci Paul, après avoir lu ton commentaire, j'ai d'abord essayé celui-là. Cela a fonctionné comme un charme :-)

0 votes

Merci Paul, cela m'a permis de gagner quelques heures en me grattant la tête comme un singe...

267voto

Benjol Points 16334

NOTE - Si cette réponse ne vous aide pas, prenez le temps de parcourir les autres réponses ajoutées depuis.

Réponse courte

Cela peut se produire si vous ajoutez une méthode à une interface dans un assemblage, puis à une classe d'implémentation dans un autre assemblage, mais que vous reconstruisez l'assemblage d'implémentation sans faire référence à la nouvelle version de l'assemblage d'interface.

Dans ce cas, DummyItem implémente une interface provenant d'un autre assemblage. La méthode SetShort a été récemment ajoutée à la fois à l'interface et au DummyItem - mais l'assemblage contenant le DummyItem a été reconstruit en faisant référence à la version précédente de l'assemblage de l'interface. La méthode SetShort est donc bien présente, mais sans la sauce magique qui la relie à la méthode équivalente dans l'interface.

Réponse longue

Si vous voulez essayer de reproduire ce phénomène, essayez ce qui suit :

  1. Créer un projet de bibliothèque de classes : InterfaceDef, ajoutez une seule classe et construisez :

    public interface IInterface
    {
        string GetString(string key);
        //short GetShort(string key);
    }
  2. Créez un deuxième projet de bibliothèque de classe : Implementation (avec une solution séparée), copier InterfaceDef.dll dans le répertoire du projet et l'ajouter comme référence de fichier, ajouter juste une classe, et construire :

    public class ImplementingClass : IInterface
    {
        #region IInterface Members
        public string GetString(string key)
        {
            return "hello world";
        }
    
        //public short GetShort(string key)
        //{
        //    return 1;
        //}
        #endregion
    }
  3. Créez un troisième projet de console : ClientCode, copiez les deux dll dans le répertoire du projet, ajoutez des références de fichiers et ajoutez le code suivant dans la méthode Main :

     IInterface test = new ImplementingClass();
     string s = test.GetString("dummykey");
     Console.WriteLine(s);
     Console.ReadKey();
  4. Exécutez le code une fois, la console dit "hello world"

  5. Décommenter le code dans les deux projets de dll et reconstruire - recopier les deux dll dans le projet ClientCode, reconstruire et essayer de nouveau. TypeLoadException se produit lors de l'instanciation de la classe ImplementingClass.

1 votes

Vous devrez peut-être ajouter que l'application Console doit être reconstruite avec les nouvelles DLL comme référence. La simple copie de la DLL ne fonctionnera pas et cela pourrait être dû à un décalage de version (c'est-à-dire qu'après avoir compilé la DLL source, la version changera). Est-ce que je comprends bien ?

0 votes

@shahkalpesh bon point - pour moi, "relancer" impliquait F5. J'ai mis à jour la réponse. Bien sûr, tout cela ne serait pas arrivé avec un outil de contrôle de source décent, mais ne me lancez pas sur ce sujet...

5 votes

Hmm, il semble que le message d'erreur de Microsoft contienne une erreur - il dit qu'une méthode de la classe "DummyItem" n'a pas d'implémentation, ce qui est manifestement faux.... en réalité, le problème est qu'une méthode de l'interface n'est pas implémentée PAR DummyItem.

37voto

Timwi Points 30896

En plus de ce que la réponse de l'auteur de la question a déjà indiqué, il peut être utile de noter ce qui suit. La raison pour laquelle cela se produit est qu'il est possible pour une classe d'avoir une méthode avec la même signature qu'une méthode d'interface sans implémenter cette méthode. Le code suivant l'illustre :

public interface IFoo
{
    void DoFoo();
}

public class Foo : IFoo
{
    public void DoFoo() { Console.WriteLine("This is _not_ the interface method."); }
    void IFoo.DoFoo() { Console.WriteLine("This _is_ the interface method."); }
}

Foo foo = new Foo();
foo.DoFoo();               // This calls the non-interface method
IFoo foo2 = foo;
foo2.DoFoo();              // This calls the interface method

0 votes

Cela a résolu le problème pour moi, avec le niveau supplémentaire d'obscurcissement que la méthode qu'il prétendait manquante était déclarée dans une interface implémentée par une classe parentale, et déclarée à nouveau dans la sous-classe. La suppression du doublon dans la sous-classe a fait disparaître l'erreur.

24voto

silent tone Points 140

J'ai obtenu ce résultat lorsque mon application n'avait pas de référence à un autre assemblage définissant une classe que la méthode du message d'erreur utilisait. L'exécution de PEVerify a donné une erreur plus utile : "Le système ne peut pas trouver le fichier spécifié".

23voto

Ben Points 81

Je suis tombé sur le même message et voici ce que nous avons trouvé : Nous utilisons des dll de tiers dans notre projet. Après la sortie d'une nouvelle version de ces dlls, nous avons modifié notre projet pour qu'il pointe vers le nouvel ensemble de dlls et nous avons compilé avec succès.

L'exception a été levée lorsque j'ai essayé d'installer l'une des classes interfacées pendant l'exécution. Nous nous sommes assurés que toutes les autres références étaient à jour, mais toujours pas de chance. Il nous a fallu un certain temps pour constater (à l'aide du navigateur d'objets) que le type de retour de la méthode figurant dans le message d'erreur était un type complètement nouveau provenant d'un nouvel assemblage non référencé.

Nous avons ajouté une référence à l'assemblage et l'erreur a disparu.

  • Le message d'erreur était assez trompeur, mais indiquait plus ou moins la bonne direction (bonne méthode, mauvais message).
  • L'exception s'est produite bien que nous n'ayons pas utilisé la méthode en question.
  • Ce qui m'amène à la question suivante : Si cette exception est levée dans tous les cas, pourquoi le compilateur ne la relève-t-il pas ?

14voto

Tim Points 91

L'autre cas où vous pouvez obtenir cette erreur est celui d'une version incorrecte d'un assemblage signé. Ce n'est pas le symptôme normal pour cette cause, mais voici le scénario dans lequel je l'ai obtenu

  • un projet asp.net contient l'assembly A et l'assembly B, B est fortement nommé

  • l'assemblage A utilise Activator.CreateInstance pour charger l'assemblage C (c'est-à-dire qu'il n'y a pas de référence à C qui est construit séparément)

  • C a été construit en se référant à une version plus ancienne de l'assemblage B que celle qui existe actuellement.

J'espère que cela aidera quelqu'un - il m'a fallu une éternité pour comprendre.

0 votes

Cela peut également se produire si un script de déploiement copie une ancienne DLL, comme lorsque plusieurs versions sont compilées dans le même ensemble de dossiers de sortie.

0 votes

Plus d'informations : J'ai ajouté un nouveau projet et étendu une interface dans une version ultérieure et j'ai construit. Je suis passé à une version antérieure et j'ai construit. Le dossier "new" était toujours là et la DLL avec l'interface modifiée du dossier "unversioned" a été copiée dans la nouvelle version par un script externe. C'est ma faute si je construis dans un dossier de vérification commun. Je l'ai trouvé en cherchant la DLL erronée dans les dossiers de l'explorateur Windows ; elle se trouvait dans un dossier qui ne faisait pas partie de la version actuelle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X