Ich benutze C # schon ziemlich lange, habe aber Folgendes nie bemerkt:
public static void Main()
{
for (int i = 0; i < 5; i++)
{
}
int i = 4; //cannot declare as 'i' is declared in child scope
int A = i; //cannot assign as 'i' does not exist in this context
}
Warum kann ich den Wert von 'i' nicht außerhalb des for-Blocks verwenden, wenn ich keine Variable mit diesem Namen deklarieren kann?
Ich dachte, dass die von einer for-Schleife verwendete Iteratorvariable nur in ihrem Umfang gültig ist.
int i, A; for(int i = 0; i < 5; i++){ } i=4; A=i
Antworten:
Der Grund, warum Sie eine Variable mit demselben Namen sowohl in der for-Schleife als auch außerhalb der for-Schleife nicht definieren dürfen, liegt darin, dass Variablen im äußeren Bereich im inneren Bereich gültig sind. Dies bedeutet, dass es innerhalb der for-Schleife zwei 'i'-Variablen geben würde, wenn dies zulässig wäre.
Siehe: MSDN-Bereiche
Speziell:
und
Und außerdem: Deklarationen lokaler Variablen (Abschnitt 8.5.1 der C # -Spezifikation)
Speziell:
(Hervorhebung von mir.)
Dies bedeutet, dass der Bereich
i
innerhalb Ihrer for-Schleife die for-Schleife ist. Während der Umfang deri
Außenseite Ihrer for-Schleife die gesamte Hauptmethode plus die for-Schleife ist. Das heißt, Sie hätten zwei Vorkommeni
innerhalb der Schleife, die gemäß den obigen Angaben ungültig sind.Der Grund, warum Sie dies nicht dürfen,
int A = i;
ist, dassint i
es nur für die Verwendung innerhalb derfor
Schleife vorgesehen ist. Somit ist es außerhalb derfor
Schleife nicht mehr zugänglich .Wie Sie sehen können, sind beide Probleme auf das Scoping zurückzuführen. Das erste Problem (
int i = 4;
) würde zu zweii
Variablen innerhalb desfor
Schleifenbereichs führen. Währendint A = i;
würde der Zugang zu einer Variablen führen , dass der Rahmen ist aus.Sie können stattdessen deklarieren
i
, dass der Gültigkeitsbereich für die gesamte Methode gilt, und ihn dann sowohl in der Methode als auch im for-loop-Bereich verwenden. Dadurch wird vermieden, dass eine der beiden Regeln verletzt wird.EDIT :
Der C # -Compiler könnte natürlich geändert werden, damit dieser Code vollständig gültig kompiliert werden kann. Immerhin ist dies gültig:
Aber wäre es wirklich vorteilhaft für Ihre Lesbarkeit und Wartbarkeit von Code, Code schreiben zu können, wie zum Beispiel:
Denken Sie hier über mögliche Fehler nach. Druckt der letzte
i
Ausdruck 0 oder 4 aus? Dies ist ein sehr kleines Beispiel, das leicht zu verfolgen und zu verfolgen ist, aber definitiv viel weniger wartbar und lesbar ist, als das Äußerei
mit einem anderen Namen deklariert zu haben .NB:
Bitte beachten Sie, dass sich die Gültigkeitsregeln von C # von den Gültigkeitsregeln von C ++ unterscheiden . In C ++ befinden sich Variablen nur im Bereich, von dem aus sie bis zum Ende des Blocks deklariert werden. Was Ihren Code zu einem gültigen Konstrukt in C ++ machen würde.
quelle
i
Variablen sein; das scheint mir offensichtlicher.i
Definition vor die for-Schleife verschoben wird, wird die innerei
Definition als ungültig markiert.J.Kommer Antwort ist richtig: kurz, es illegal ist für eine lokale Variable in einen deklariert wird lokalen Variable Deklarationsraumes , die überlappt eine anderen lokalen Variable Deklarationsraum , der ein lokal mit dem gleichen Namen hat.
Es gibt eine zusätzliche Regel von C #, die auch hier verletzt wird. Die zusätzliche Regel lautet, dass es unzulässig ist, einen einfachen Namen zu verwenden, um auf zwei verschiedene Entitäten in zwei verschiedenen überlappenden Deklarationsräumen für lokale Variablen zu verweisen. Ihr Beispiel ist also nicht nur illegal, sondern auch illegal:
Weil jetzt der einfache Name "x" im Deklarationsraum der lokalen Variablen von "y" verwendet wurde, um zwei verschiedene Dinge zu bedeuten - "this.x" und das lokale "x".
Weitere Analysen dieser Probleme finden Sie unter http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/ .
quelle
int y = this.x;
this.x
ist kein einfacher Name .Es gibt eine Möglichkeit,
i
die Methode nach der Schleife zu deklarieren und zu verwenden :Sie können dies in Java tun (es könnte von C stammen, da bin ich mir nicht sicher). Es ist natürlich ein bisschen chaotisch für einen Variablennamen.
quelle
Wenn Sie
i
vor Ihrerfor
Schleife deklariert haben , sollte es Ihrer Meinung nach noch gültig sein, sie innerhalb der Schleife zu deklarieren?Nein, denn dann würde sich der Umfang der beiden überschneiden.
Was nicht möglich
int A=i;
ist, liegt einfach daran, dass esi
nur in derfor
Schleife existiert, wie es sein sollte.quelle
Zusätzlich zu J.Kommers Antwort (+1 übrigens). Es gibt dies im Standard für den NET-Bereich:
Daher ist das im for-Schleifen-Header dekalierte int i nur während des for-Schleifenblocks im Gültigkeitsbereich, ABER seine Lebensdauer dauert bis zur
Main()
Vervollständigung des Codes.quelle
Der einfachste Weg, darüber nachzudenken, besteht darin, die äußere Deklaration von I über die Schleife zu verschieben. Es sollte dann offensichtlich werden.
Es ist in beiden Fällen der gleiche Bereich und kann daher nicht durchgeführt werden.
quelle
Auch die Regeln von C # sind für die strikte Programmierung oft nicht erforderlich, dienen jedoch dazu, Ihren Code sauber und lesbar zu halten.
Zum Beispiel hätten sie es so machen können, dass wenn Sie es nach der Schleife definieren, es in Ordnung ist, aber jemand, der Ihren Code liest und die Definitionszeile verpasst hat, könnte denken, dass es mit der Variablen der Schleife zu tun hat.
quelle
Kommers Antwort ist technisch korrekt. Lassen Sie es mich mit einer lebendigen Blind-Screen-Metapher umschreiben.
Zwischen dem for-Block und dem umschließenden äußeren Block befindet sich ein Einweg-Blindbildschirm, sodass der Code innerhalb des for-Blocks den äußeren Code sehen kann, der Code im äußeren Block jedoch den Code im Inneren nicht sehen kann.
Da der äußere Code nicht nach innen sehen kann, kann er nichts verwenden, was im Inneren deklariert ist. Da der Code im for-Block sowohl innen als auch außen sichtbar ist, kann eine an beiden Stellen deklarierte Variable nicht eindeutig namentlich verwendet werden.
Entweder du siehst es nicht oder du C #!
quelle
Betrachten Sie es so, als könnten Sie ein
int
in einemusing
Block deklarieren :Da dies
int
jedoch nicht implementiert istIDisposable
, kann dies nicht durchgeführt werden. Es kann jedoch jemandem helfen, zu visualisieren, wie eineint
Variable in einem privaten Bereich platziert wird.Ein anderer Weg wäre zu sagen:
Hoffe, dies hilft zu visualisieren, was los ist.
Ich mag diese Funktion wirklich, da das Deklarieren von
int
aus derfor
Schleife den Code schön und eng hält.quelle
using
ist ganz ok, obwohl die Semantik ziemlich unterschiedlich ist (was vielleicht der Grund ist, warum er downvotiert wurde). Beachten Sie, dass diesif (true)
redundant ist. Entfernen Sie es und Sie haben einen Scoping-Block.