Ich habe eine .NET-Anwendung, die eine Assembly (.dll) verwendet, die eine Methode definiert:
%Vor%Angenommen, diese Methodensignatur ändert sich und enthält einen String Rückgabetyp:
%Vor%Warum schlägt der Code, der diese Methode verwendet, für eine System.MissingMethodException fehl?
Es scheint mir, dass an allen Aufrufstellen dieser Methode der Rückgabewert nicht verwendet wurde (da er vorher nicht existierte).
Warum bricht diese Änderung den Code dann?
Weil du einen api-Wechsel gemacht hast. Sie haben entweder die Methodensignatur in einer Basisklasse oder in einer Schnittstelle geändert.
Die Anrufer sind mit dieser Methode verbunden. In IL ist eine Methodenreferenz nicht nur eine Referenz auf einen Typ und seine Methode mit einem Index für die Methode, sondern die Referenzen der Aufrufermethoden enthalten auch die vollständige Methodensignatur.
Diese Änderung ist daher durch eine Neukompilierung aller Assemblys, die diese Methode aufrufen, reparierbar, aber Sie erhalten Laufzeitausnahmen, wenn Sie nur die geänderte Assembly neu kompilieren und hoffen, dass die verwendenden Assemblys die geänderte Methodensignatur magisch übernehmen. Dies ist nicht der Fall, da die Methodenreferenz die vollständige Methodensignatur und den Definitionstyp enthält.
Es ist mir auch passiert. Sie haben Recht, dass niemand den Rückgabetyp verwenden kann, daher ist diese Änderung sicher, aber Sie müssen alle betroffenen Ziele neu kompilieren.
Die anderen Antworten, die angeben, dass Sie die Signatur einer Methode geändert haben und daher die Aufrufer neu kompilieren müssen, sind korrekt. Ich dachte, ich könnte einige zusätzliche Informationen über dieses Bit Ihrer Frage hinzufügen:
Es scheint mir, dass an allen Aufrufstellen dieser Methode der Rückgabewert nicht verwendet wurde (da er vorher nicht existierte).
Das stimmt genau. Betrachten Sie nun diese Frage: Wie schreibt man Code, der keine Daten verwendet ? Sie scheinen unter der völlig falschen Annahme zu arbeiten, dass keinen Wert verwenden keinen Code erfordert, aber keinen Wert zu verwenden, erfordert Code!
Angenommen, Sie haben Methoden:
%Vor%und Sie haben einen Anruf
%Vor%Was passiert auf der IL-Ebene ? das Folgende:
Angenommen, Sie tun jetzt:
%Vor%Was passiert? Gleiches :
Aber es gibt keine Anweisung, die den Wert irgendwo auf dem Stack speichert, also müssen wir eine Pop-Anweisung ausgeben:
Angenommen, Sie rufen
an %Vor%Was passiert?
Siehst du jetzt, warum eine Änderung der Methode von void returning auf value return eine brechende Änderung ist? Jeder Aufrufer muss jetzt den nicht verwendeten Wert vom Stapel entfernen . Wenn Sie nothing mit Daten ausführen, müssen Sie es weiterhin vom Stapel löschen . Sie verschieben den Stapel falsch, wenn Sie diesen Wert nicht deaktivieren. Die CLR erfordert, dass der Stapel zu Beginn jeder Anweisung leer ist, um sicherzustellen, dass diese Art von Fehlausrichtung nicht auftritt.
Wenn es keine Reflexion gibt, aber die Verknüpfung statisch ist (ich nehme das aus der Beschreibung an), wird die Laufzeit versuchen, eine Methode zu finden, die die exakte Signatur verwendet. Es funktioniert nur wie% callvirt
von CIL funktioniert.
Es ist dann egal, ob der Wert verbraucht wird oder nicht - die Laufzeitumgebung kann void YourClass::DoSomething()
nicht finden und versucht nicht einmal nach string YourClass::DoSomething()
zu suchen.
Wenn eine solche Änderung möglich war, könnten Sie die Laufzeit leicht sprengen, indem Sie Stack-Unterläufe / Überläufe verursachen.
Weil Sie die Methodensignatur geändert haben.
Wenn der externe Code eine Methode finden muss, muss er sicherstellen, dass der Aufruf korrekt ist. Es speichert einige dieser Informationen als eine Signatur zum Zeitpunkt der Kompilierung - die Signaturinformationen enthalten den Rückgabetyp (unabhängig davon, ob er tatsächlich irgendwo verwendet wird).
Was die CLR betrifft, gibt es keine Methode mit einem void return type - daher die MissingMethodException
.