Warum müssen lokale Variablen initialisiert werden, aber Felder nicht?
Wenn ich einen bool in meiner Klasse, nur so etwas wie bool check
es standardmäßig auf false gesetzt.
Wenn ich die gleichen bool innerhalb meiner Methode bool check
(statt innerhalb der Klasse), bekomme ich einen Fehler "Verwendung der nicht zugewiesenen lokalen Variablen prüfen". Warum?
InformationsquelleAutor der Frage nachime | 2015-06-13
Du musst angemeldet sein, um einen Kommentar abzugeben.
Yuval und David ' s Antworten sind im wesentlichen richtig; Fazit:
Einen Kommentator David ' s Antwort fragt, warum es unmöglich zu erkennen die Verwendung einer nicht zugewiesenen Bereich über der statischen Analyse; dies ist der Punkt, den ich noch weiter ausbauen wollen, auf diese Antwort.
First off, für jede variable, lokale oder anderweitig, ist es in der Praxis unmöglich zu bestimmen genauob eine variable zugewiesen oder nicht zugewiesen. Bedenken Sie:
Die Frage "ist x zugeordnet?" ist äquivalent zu "nicht M() true zurück?" Nehmen wir nun an, M() gibt true zurück, wenn Fermat ' s Last Theorem gilt für alle ganzen zahlen kleiner als eleventy gajillion, und andernfalls false. Um zu bestimmen, ob x ist definitiv zugewiesen, muss der compiler im wesentlichen produzieren ein Beweis für Fermat ' s Last Theorem. Der compiler ist nicht so schlau.
So, was der compiler tut, statt für die einheimischen ist implementiert einen Algorithmus, der schnellund überschätztwenn eine lokale ist nicht definitiv zugewiesen. Das heißt, es hat einige false-positives, wo es heißt "ich kann nicht beweisen, dass diese lokale zugeordnet ist," obwohl du und ich wissen es. Zum Beispiel:
Angenommen, N() gibt eine Ganzzahl zurück. Sie und ich wissen, dass N() * 0 ist 0, aber der compiler weiß nicht, dass. (Hinweis: die C# - 2.0-compiler hat wissen, dass, aber ich entfernt, Optimierung, da sich die Spezifikation nicht sagendass der compiler weiß, dass.)
Alle Recht, also, was wissen wir bisher? Es ist unpraktisch, für die einheimischen, bekommen eine genaue Antwort, aber wir können nicht überschätzen-zugeordnet-seins, Sie sind günstig und bekommen ein Recht gutes Ergebnis, Irrt auf der Seite "machen Sie das unklar-Programm". Das ist gut so. Warum nicht das gleiche für die Felder? Das heißt, eine eindeutige Zuordnung checker, überschätzt Billig?
Gut, wie viele Möglichkeiten gibt es für eine lokale initialisiert werden? Es kann zugewiesen werden, innerhalb des Textes der Methode. Es kann zugewiesen werden, in einen lambda-Ausdruck im text der Methode, die lambda kann nie aufgerufen werden, so dass diese Aufgaben nicht relevant sind. Oder es kann überschritten werden, als "out" zu anothe Methode, an welchem Punkt wir können davon ausgehen, es wird vergeben, wenn die Methode gibt in der Regel. Das sind ganz klare Punkte, an denen die lokalen zugewiesen, und Sie sind es, direkt im gleichen Methode, die den lokalen deklariert ist. Die Bestimmung definitive Zuordnung für einheimische erfordert nur lokale Analyse. Methoden dazu neigen, kurz zu sein-weit weniger als einer million Zeilen code in einer Methode-und so die Analyse der gesamten Methode ist sehr schnell.
Nun was ist mit Feldern? Kann-Felder werden bei der Initialisierung im Konstruktor der Kurs. Oder ein Feld-Initialisierer. Oder der Konstruktor-Aufruf wird eine Instanz-Methode, initialisiert die Felder. Oder der Konstruktor nennen kann virtuellen Methode, die initailizes die Felder. Oder der Konstruktor kann eine Methode aufrufen in einer anderen Klassedie möglicherweise in einer Bibliothekinitialisiert die Felder. Statische Felder werden bei der Initialisierung im statischen Konstruktoren. Statische Felder können initialisiert werden, indem anderen statische Konstruktoren.
Im wesentlichen die Initialisierung für ein Feld könnte überall im gesamten Programmauch im virtuelle Methoden deklariert werden, die in Bibliotheken, die noch nicht geschrieben worden, noch:
Ist es ein Fehler zu kompilieren, die diese Bibliothek? Wenn ja, wie ist BarCorp soll um den Fehler zu beheben? Durch die Zuordnung eines default-Wert zu x? Aber das ist, was der compiler tut, schon.
Angenommen, diese Bibliothek ist legal. Wenn FooCorp schreibt
ist dass ein Fehler? Wie ist der compiler soll, um das herauszufinden? Der einzige Weg ist zu einem ganze Programm Analysedass tracks die Initialisierung von statischen jedes Feld auf jeder mögliche Pfad durch das Programmeinschließlich Pfade, die Einbeziehung der Wahl von virtuellen Methoden zur Laufzeit. Dieses problem kann man willkürlich hart; es kann sich um simulierte Ausführung von Millionen von Steuern wegen. Die Analyse der lokalen Kontrolle fließt dauert Mikrosekunden und hängt von der Größe der Methode. Die Analyse von global-control-flows kann Stunden dauern, denn es hängt von der Komplexität der jede Methode in das Programm und alle Bibliotheken.
Also warum nicht eine billigere Analyse, die nicht zu analysieren, das ganze Programm, und nur überschätzt noch schwerer? Gut, schlagen Sie einen Algorithmus, der arbeitet, macht ihn das nicht zu schwer zu schreiben, eine korrekte Programm, das tatsächlich kompiliert, und das design-team kann es prüfen. Ich weiß nicht, von solchen Algorithmus.
Nun, der Kommentator schlägt vor, dass "es erforderlich, einen Konstruktor initialisiert alle Felder". Das ist keine schlechte Idee. In der Tat, es ist wie eine nicht schlechte Idee, dass C# bereits, dass die Funktion für Strukturen. Ein struct-Konstruktor ist erforderlich, um auf jeden Fall, ordnen Sie alle Felder, durch die Zeit, die ctor gibt normalerweise; der default-Konstruktor initialisiert alle Felder auf Ihre Standardwerte zurück.
Was über die Klassen? Gut, Woher wissen Sie, dass ein Konstruktor initialisiert hat ein Feld? Die ctor-Aufruf könnte ein virtuelle Methode die Felder zu initialisieren, und jetzt sind wir wieder in der gleichen position, die wir waren, bevor. Strukturen nicht haben, die von abgeleiteten Klassen; Klassen könnten. Ist eine Bibliothek, die eine abstrakte Klasse benötigt, enthalten einen Konstruktor initialisiert alle seine Felder? Wie sieht die abstrakte Klasse wissen, welche Werte die Felder initialisiert werden?
John schlägt vor, Sie einfach zu verbieten Aufruf von Methoden in einem ctor, bevor Sie die Felder werden initialisiert. Also, zusammenfassend kann man sagen, unsere Optionen sind:
Das design-team wählte die Dritte option.
InformationsquelleAutor der Antwort Eric Lippert
Da der compiler versucht, Sie daran zu hindern, Fehler zu machen.
Nicht initialisieren eine variable, um
false
nichts ändern in diesem besonderen Weg der Ausführung? Wahrscheinlich nicht, wenn man bedenktdefault(bool)
ist sowieso falsch, aber es zwingt Sie zu bewusstdass dies geschieht. Die .NET-Umfeld verhindert, dass Sie Zugriff auf "Müll-memory", da wird es initialisiert einen beliebigen Wert auf die Standardeinstellung. Aber noch vorstellen, das war ein Referenz-Typ, und Sie würde übergeben Sie ein nicht initialisiert (null) - Wert an eine Methode erwartet einen nicht-null, und erhalten eine NRE zur Laufzeit. Der compiler ist einfach zu versuchen, dass zu verhindern, die Tatsache zu akzeptieren, dass dies kann manchmal dazu führen, dassbool b = false
Aussagen.Eric Lippert spricht über dieses in einem blog-post:
Warum nicht, diese gelten für ein Klasse-Feld? Gut, ich nehme an, musste die Linie gezogen irgendwo, und lokale Variablen-Initialisierung sind viel leichter zu diagnostizieren und richtig, im Gegensatz zu class-Felder. Der compiler könnte dies tun, aber denken Sie an all die möglichen Prüfungen würde es brauchen, um machen, (wo einige von Ihnen sind unabhängig von der Klasse code selbst), um zu beurteilen, ob jedes Feld in einer Klasse initialisiert wird. Ich bin kein compiler-designer, aber ich bin sicher, es wäre definitiv härterdenn es gibt viele Fälle, die berücksichtigt und erledigt werden, in eine zeitnah als gut. Für jede Funktion, die Sie entwerfen, schreiben, testen und bereitstellen und den Wert der Umsetzung dieser im Gegensatz zu den Anstrengungen, die wäre nicht würdig und kompliziert.
InformationsquelleAutor der Antwort Yuval Itzchakov
Die kurze Antwort ist, dass code den Zugriff auf uninitialised lokale Variablen können vom compiler erkannt, in eine zuverlässige Möglichkeit, mit Hilfe statischer Analyse. In der Erwägung, dass dies nicht der Fall Felder. Damit der compiler erzwingt den ersten Fall, nicht aber die zweite.
Dies ist nicht mehr als eine design-Entscheidung von C# - Sprache, wie erklärt von Eric Lippert. Die CLR und die .NET-Umgebung, die es nicht benötigen. VB.NET zum Beispiel kompiliert einwandfrei mit uninitialised lokalen Variablen, und in Wirklichkeit ist der CLR initialisiert alle uninitialised Variablen auf default-Werte.
Das gleiche kann auftreten, mit C#, aber die Sprache, die Designer entschieden, nicht an. Der Grund dafür ist, dass Variablen initialisiert sind eine große Quelle von bugs und so, durch Beauftragung der Initialisierung der compiler hilft zu reduzieren auf zufälligen Fehlern.
Warum also nicht diese obligatorische explizite Initialisierung passiert mit Feldern, die innerhalb einer Klasse? Ganz einfach, weil dass die explizite Initialisierung auftreten konnte, während der Konstruktion, über eine Eigenschaft aufgerufen wird durch ein Objekt-Initialisierer, oder auch, wenn eine Methode aufgerufen wird, lange nach der Veranstaltung. Der compiler kann nicht verwenden der statischen Analyse, um zu bestimmen, wenn jeder mögliche Pfad durch den code, führt der Variablen explizit initialisiert werden, bevor uns. Sie bekommen es falsch wäre ärgerlich, als könnte der Entwickler überlassen werden, mit gültigen code, der nicht kompiliert wird. Damit C# nicht durchsetzen und die CLR ist Links automatisch zu initialisieren-Felder einen default-Wert, falls nicht explizit festgelegt.
C#'s die Durchsetzung von lokalen Variablen-Initialisierung begrenzt ist, die oft fängt den Entwicklern aus. Betrachten Sie die folgenden vier Zeilen code:
In der zweiten Zeile der code nicht kompiliert wird, als er versucht zu Lesen, eine string-variable (uninitialised. Die vierte Zeile code kompiliert werden just fine aber, wie
array
initialisiert wurde, aber nur mit default-Werten. Da der default-Wert von string null ist, erhalten wir eine exception zur Laufzeit. Jeder, der Zeit damit verbracht hier auf Stack Overflow wird wissen, dass diese explizite/implizite Initialisierung Inkonsistenz führt zu sehr vielen "Warum bekomme ich eine "Object reference not set to an instance of an object" Fehler?" Fragen.InformationsquelleAutor der Antwort David Arno
Guten Antworten oben, aber ich dachte, ich würde post eine viel einfachere/kürzere Antwort für Menschen, die zu faul zum Lesen ist sehr lang (wie ich).
Klasse
Eigenschaft
Boo
kann oder nicht wurden initialisiert im Konstruktor. Also, wenn es findetreturn Boo;
es nicht übernehmendass es initialisiert wurde. Es ist einfach unterdrückt den Fehler.Funktion
Den
{ }
Zeichen definieren den Umfang des einen code-block. Der compiler geht den Filialen dieser{ }
Blöcke verfolgen von Sachen. Es kann leicht sagen, dassBoo
wurde nicht initialisiert. Der Fehler wird dann ausgelöst.Warum der Fehler vorhanden???
Den Fehler eingeführt wurde, um reduzieren Sie die Anzahl von Zeilen code erforderlich, um source-code sicher. Ohne den Fehler oben würde wie folgt Aussehen.
Aus der Anleitung:
Referenz: https://msdn.microsoft.com/en-us/library/4y7h161d.aspx
InformationsquelleAutor der Antwort cgTag