Warum verhält sich eine for-Schleife bei der Migration von VB.NET-Code nach C # anders?

87

Ich bin gerade dabei, ein Projekt von Visual Basic nach C # zu migrieren, und ich musste ändern, wie eine verwendete forSchleife deklariert wird.

In VB.NET wird die forSchleife unten deklariert:

Dim stringValue As String = "42"

For i As Integer = 1 To 10 - stringValue.Length
   stringValue = stringValue & " " & CStr(i)
   Console.WriteLine(stringValue)
Next

Welche Ausgänge:

42 1
42 1 2
42 1 2 3
42 1 2 3 4
42 1 2 3 4 5
42 1 2 3 4 5 6
42 1 2 3 4 5 6 7
42 1 2 3 4 5 6 7 8

In C # wird die forSchleife unten deklariert:

string stringValue = "42";

for (int i = 1; i <= 10 - stringValue.Length; i ++)
{
   stringValue = stringValue + " " + i.ToString();
   Console.WriteLine(stringValue);
}

Und die Ausgabe:

42 1
42 1 2
42 1 2 3

Dies ist offensichtlich nicht korrekt, daher musste ich den Code geringfügig ändern und eine Ganzzahlvariable einfügen, die die Länge der Zeichenfolge enthält.

Bitte beachten Sie den Code unten:

string stringValue = "42";
int stringValueLength = stringValue.Length;

for (int i = 1; i <= 10 - stringValueLength; i ++)
{
   stringValue = stringValue + " " + i.ToString();
   Console.WriteLine(stringValue);
}

Und die Ausgabe:

42 1
42 1 2
42 1 2 3
42 1 2 3 4
42 1 2 3 4 5
42 1 2 3 4 5 6
42 1 2 3 4 5 6 7
42 1 2 3 4 5 6 7 8

Jetzt geht es um die Frage, wie sich Visual Basic in Bezug auf Visual Basic unter Verwendung der stringValue.LengthBedingung in der forSchleife von C # unterscheidet, obwohl sich die Länge der Zeichenfolge bei jedem Auftreten der Schleife ändert. Wenn ich in C # stringValue.Lengthdie forBedingung in der Schleife verwende, ändert sich der anfängliche Zeichenfolgenwert jedes Mal, wenn die Schleife auftritt. Warum ist das?

sle423
quelle
7
Microsoft umreißt klar, was Ihr Problem ist ...
Çöđěxěŕ
39
@ Çöđěxěŕ: Hör bitte auf. Wenn das robotergesteuerte Entfernen von Tags aus dem Titel ohne Berücksichtigung des Kontexts hilfreich wäre, würde die Website dies tun.
Ry-
11
@ Çöđěxěŕ können Sie einige Informationen darüber finden Sie hier
pushkin
35
@ Çöđěxěŕ Ich glaube nicht, dass sich die beiden Beiträge widersprechen. Der Punkt ist: Kleben Sie nicht ungeschickt ein Tag in den Titel wie "Frage zu diesem Ding - Tag". Wenn der Titel jedoch ein vollständiger Satz ist, der das Tag enthält, ist er manchmal in Ordnung. "Warum verhält sich die for-Schleife bei der Migration anders?" Fühlt sich wie ein viel zu allgemeiner Titel an.
Puschkin
26
@ Çöđěxěŕ "Migrieren von VB.NET-Code nach C #" ist eindeutig eine vollständige Phrase, die dem Titel nützliche Informationen hinzufügt. Nehmen Sie keine Änderungen vor, die die Klarheit beeinträchtigen. Hoffentlich ist dieser Begriff so vernünftig, dass wir keinen Meta-Post benötigen, um ihn zu sichern.
jpmc26

Antworten:

115

In C # wird die Schleifenrandbedingung bei jeder Iteration ausgewertet. In VB.NET wird es nur beim Eintritt in die Schleife ausgewertet.

In der C # -Version in der Frage stringValuewird der endgültige Wert der Schleifenvariablen geändert , da die Länge von in der Schleife geändert wird.

In VB.NET ist die endgültige Bedingung inklusive, sodass Sie sie <=anstelle von <C # verwenden würden.

Die Endbedingungsbewertung in C # hat die Konsequenz, dass selbst wenn sie nicht variiert, aber teuer zu berechnen ist, sie nur einmal vor der Schleife berechnet werden sollte.

Andrew Morton
quelle
Danke für die Antwort. Mir ist jetzt klar, <=dass ich mit using die gleiche Ausgabe wie der VB-Code ausführen kann. Ich bin jedoch mehr daran interessiert zu wissen, warum ich die Ganzzahlvariable deklarieren musste und VBnicht. Ich werde meine Frage aktualisieren, um die gleiche Ausgabe anzuzeigen.
sle423
@ sle423 Der Grund ist im ersten Satz meiner Antwort angegeben. Da die Länge von stringValuein der Schleife geändert wird, wird der endgültige Wert der Schleifenvariablen geändert.
Andrew Morton
1
Entschuldigung, danke für diese Antwort. Und danke, dass Sie es für mich ausführlicher ausgearbeitet haben.
sle423
1
@ sle423 Ich habe das in die Antwort aufgenommen, da es es tatsächlich klarstellt.
Andrew Morton
22

Jetzt geht es um die Frage, wie sich VB in Bezug auf VB mithilfe der Zeichenfolge stringValue.Length in der for-Schleife von C # unterscheidet, obwohl sich die Länge der Zeichenfolge jedes Mal ändert, wenn die Schleife auftritt.

Gemäß der VB.NET- Dokumentation:

Wenn Sie den Wert von counterwhile in einer Schleife ändern , ist Ihr Code möglicherweise schwieriger zu lesen und zu debuggen. Ändern des Wertes start, endoder stepwirkt sich nicht auf die Iteration Werte , die bestimmt wurden , wenn die Schleife zuerst eingegeben wurde.

Der Wert von To 10 - stringValue.Lengthwird also einmal ausgewertet und wiederverwendet, bis die Schleifen beendet sind.

Schauen Sie sich jedoch die Anweisung von c # an

Wenn das for_conditionnicht vorhanden ist oder die Bewertung ergibt true, wird die Kontrolle auf die eingebettete Anweisung übertragen. Wann und wenn die Steuerung den Endpunkt der eingebetteten Anweisung erreicht (möglicherweise nach Ausführung einer continue-Anweisung), werden die Ausdrücke der for_iterator, falls vorhanden, nacheinander ausgewertet, und dann wird eine weitere Iteration durchgeführt, beginnend mit der Auswertung der for_conditionim Schritt über.

Dies bedeutet im Grunde, dass der Zustand ; i <= 10 - stringValueLength;jedes Mal erneut bewertet wird.

Wie Sie gesehen haben, müssen Sie, wenn Sie den Code replizieren möchten, den endgültigen Zähler in c # deklarieren, bevor Sie die Schleife starten.

Camilo Terevinto
quelle
11

Um das Beispiel verständlicher zu machen, werde ich beide for-Schleifen in C # while-Schleifen konvertieren .

VB.NET

string stringValue = "42";

int min = 1;
int max = 10 - stringValue.Length;
int i = min;
while (i <= max)
{
    stringValue = stringValue + " " + stringValue.Length.ToString();
    Console.WriteLine(stringValue);
    i++;
}

C #

string stringValue = "42";

int i = 1;
while (i <= 10 - stringValue.Length)
{
    stringValue = stringValue + " " + stringValue.Length.ToString();
    Console.WriteLine(stringValue);
    i++;
}

Der Unterschied ist dann:

VB.NET speichert den Maximalwert für zwischen i, aber C # berechnet ihn jedes Mal neu.

Maxime Recuerda
quelle
2
Sie müssen keine Schleifen in while konvertieren
Panagiotis Kanavos
10
Es hat mir geholfen, das zu verstehen for loops, ich denke, sie sind viel verständlicher. Aus diesem Grund habe ich die Beispiele in "übersetzt" while loops, um das Verständnis zu erleichtern.
Maxime Recuerda
7

Weil das forin VB eine andere Semantik ist als das forin C # (oder einer anderen C-ähnlichen Sprache)

In VB forerhöht die Anweisung speziell einen Zähler von einem Wert zu einem anderen.

In C, C ++, C # usw. forwertet die Anweisung einfach drei Ausdrücke aus:

  • Der erste Ausdruck ist üblicherweise eine Initialisierung
  • Der zweite Ausdruck wird zu Beginn jeder Iteration ausgewertet, um festzustellen, ob die Endbedingung erfüllt ist
  • Der dritte Ausdruck wird am Ende jeder Iteration ausgewertet, die üblicherweise ein Inkrementierer ist.

In VB, Sie müssen eine numerische Variable liefern , die gegen einen Endwert getestet werden kann und bei jeder Iteration erhöht

In C, C ++, C # usw. sind die drei Ausdrücke minimal eingeschränkt. Der bedingte Ausdruck muss als wahr / falsch (oder als Ganzzahl Null / Nicht-Null in C, C ++) ausgewertet werden. Sie müssen überhaupt keine Initialisierung durchführen, Sie können jeden Typ über einen beliebigen Wertebereich iterieren, einen Zeiger oder eine Referenz über eine komplexe Struktur iterieren oder überhaupt nichts iterieren.

In C # usw. muss der Bedingungsausdruck bei jeder Iteration vollständig ausgewertet werden, aber in VB muss der Endwert des Iterators zu Beginn ausgewertet werden und muss nicht erneut ausgewertet werden.

C Robinson
quelle