3 Stimmen

Warum kann Down-Casting nicht zur Kompilierzeit überprüft werden?

Warum kann der Compiler nicht zur Compilierzeit erkennen, dass obj verweist auf ein Objekt des Typs B und meldet daher einen Fehler, wenn wir versuchen, ihn in den Typ A ?

public class A { }
public class B { }

static void Main(string[] args)
{
   B b = new B();
   object obj = (object)b;
   A a = (A)obj; // exception

Vielen Dank

14voto

Tomas Petricek Punkte 233658

Aufgrund der Halteproblem . Das bedeutet im Wesentlichen, dass Sie nicht entscheiden können, welchen Ausführungspfad das Programm nehmen wird (und es gibt einen mathematischen Beweis dafür). Zum Beispiel kann der folgende Code korrekt sein oder auch nicht:

object o = SomeTest() ? (new A()) : (new B());
A a = (A)o;

Wenn die SomeTest Methode gibt immer zurück true dann ist sie korrekt. Leider ist es nicht möglich, das zu entscheiden. Es gibt jedoch eine Menge Forschung auf diesem Gebiet. Auch wenn es nicht sein kann toujours überprüft, gibt es Tools, die manchmal überprüfen können, ob etwas immer gelingt, oder die Ihnen ein Beispiel für einen Ausführungspfad geben, bei dem die Annahme fehlschlägt.

Ein gutes Beispiel für diese Technik sind Code Verträge die ein Teil von Visual Studio 2010 sein wird. Ich glaube, Sie können sie verwenden, um zu beweisen, dass Ihr Downcasting korrekt ist. Allerdings gibt es keine explizite Unterstützung für diese - obwohl, es wäre nützlich sein!

7voto

Eric Lippert Punkte 628543

Lassen Sie mich die Frage umdrehen: Wenn der Compiler das beweisen könnte, warum bräuchten wir dann überhaupt Casts? Der Zweck eines Casts ist es, dem Compiler zu sagen: "Ich weiß mehr über diesen Code als du, und ich verspreche dir, dass dieser Cast gültig ist. Ich bin mir dieser Tatsache so sicher, dass ich bereit bin, dich Code generieren zu lassen, der eine Exception auslöst, wenn ich mich irre." Der Compiler kann nicht beweisen, dass der Cast gültig ist, weil der Cast für Szenarien, bei denen der Compiler nicht beweisen kann, dass sie gültig sind.

6voto

John Saunders Punkte 159011

Sie möchten, dass der Compiler den Kontrollfluss verfolgt und im Voraus feststellt, dass der Cast eine Ausnahme verursachen wird? Wozu die Mühe? Bei einem echten Programm wird der Kontrollfluss zu kompliziert sein, um dies herauszufinden.

6voto

Ben Karel Punkte 4451

Ein Compiler könnte sicherlich Prüfungen implementieren, die in trivialen Fällen wie diesem funktionieren würden. Aber es ist unwahrscheinlich, dass dies dem "echten" Code sehr helfen würde, da Programmierer selten so offensichtlich falschen Code schreiben.

Um kompliziertere Fälle zu behandeln, müsste ein Compiler eine viel kompliziertere Analyse durchführen. Dies ist für den Compiler-Autor schwieriger zu bewerkstelligen und auch für Ihren Rechner langsamer, und es immer noch nicht in der Lage wäre, jeden möglichen Fehlwurf aufzufangen. Und da der meiste Code keine leicht identifizierbaren Fehler dieser Art aufweist, ist es nicht klar, ob der Nutzen die Kosten für die Analyse wert ist.

Zwei Nachteile der komplizierteren statischen Analyse sind Fehlermeldungen und falsch positive Ergebnisse. Erstens, ein Werkzeug zu haben erklären ein Problem im Code zu finden, ist oft um eine Größenordnung schwieriger, als das Werkzeug lediglich auf das Problem zu prüfen. Zweitens wird es sehr viel wahrscheinlicher, dass das Werkzeug Dinge anzeigt, die in der Praxis nie ein Problem darstellen, da sich die überprüften Probleme von "das Schlimme X wird auf jeden Fall passieren" zu "das Schlimme Y könnte passieren" verändern.

Es gibt einen interessanten Aufsatz, der von einem Unternehmen geschrieben wurde, das statische Analysetools verkauft und aus der akademischen Forschung hervorgegangen ist. Sie fanden heraus, dass sie mit komplizierteren Analysen oft weniger Umsatz machten! Ein paar Milliarden Codezeilen später: Statische Analyse zur Fehlersuche in der realen Welt

2voto

Aaronaught Punkte 118136

Selbst statische Analysetools können dieses Problem nicht lösen. Was ist, wenn Ihr Code Reflection verwendet?

void Test(string typeName)
{
    Type t = Type.GetType(typeName);
    object obj = Activator.CreateInstance(t);
    A a = (A)obj;
    // etc.
}

Wird dies eine Ausnahme auslösen? Es gibt absolut keine Möglichkeit, die Antwort zu erfahren, ohne es tatsächlich auszuführen. Keine noch so gute Code-Pfad-Analyse wird einen Fehler aufdecken, der von der Wert eines bestimmten Parameters. Und wenn Sie Folgendes tun müssen laufen. den Code, um den Fehler zu erkennen, dann ist es ein Laufzeitfehler, nicht zur Kompilierzeit.

Dies ist genau der Grund, warum Sie Test Ihr Code. Compiler können nicht sicherstellen, dass Ihr Code richtig nur, dass er syntaktisch gültig ist und den Regeln der Grammatik folgt.

Und obwohl dies wie ein erfundenes Beispiel erscheinen mag, wird Reflection heutzutage so gut wie überall eingesetzt, von Ihrem O/R-Mapper bis zu Ihrem DI-Framework. In einer modernen Anwendung ist es eigentlich ziemlich üblich, den Typ einer Instanz nicht zu kennen, oder zumindest nicht den spezifische Betonart bis zur Laufzeit.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X