web-dev-qa-db-fra.com

Pourquoi une boucle for se comporte-t-elle différemment lors de la migration du code VB.NET vers C #?

Je suis en train de migrer un projet de Visual Basic vers C # et j'ai dû modifier la manière dont une boucle for utilisée est déclarée.

Dans VB.NET, la boucle for est déclarée ci-dessous:

Dim stringValue As String = "42"

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

Quelles sorties:

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

En C #, la boucle for est déclarée ci-dessous:

string stringValue = "42";

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

Et la sortie:

42 1
42 1 2
42 1 2 3

Ceci n’est évidemment pas correct, aussi j’ai dû changer le code très légèrement et inclure une variable entière qui contiendrait la longueur de la chaîne.

Veuillez consulter le code ci-dessous:

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

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

Et la sortie:

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

Maintenant ma question résout comment Visual Basic diffère de C # en termes de Visual Basic en utilisant la condition stringValue.Length dans la boucle for même si la longueur de la chaîne est modifiée à chaque fois. Tandis qu'en C #, si j'utilise le stringValue.Length dans la condition de boucle for, la valeur de chaîne initiale est modifiée à chaque fois que la boucle se produit. Pourquoi est-ce?

86
slee423

En C #, la condition de limite de boucle est évaluée à chaque itération. En VB.NET, il n’est évalué qu’à l’entrée de la boucle.

Ainsi, dans la version C # de la question, étant donné que la longueur de stringValue est modifiée dans la boucle, la valeur de la variable de boucle finale sera modifiée.

Dans VB.NET, la condition finale est inclusive. Vous devez donc utiliser <= au lieu de < en C #.

L’évaluation de la condition finale en C # a pour corollaire que, même si elle ne varie pas mais qu’elle est coûteuse à calculer, elle devrait être calculée une seule fois avant la boucle.

115
Andrew Morton

Maintenant ma question résout comment VB diffère de C # en termes de VB en utilisant la condition stringValue.Length dans la boucle for, même si la longueur de la chaîne change à chaque fois.

Selon la documentation VB.NET :

Si vous modifiez la valeur de counter au sein d'une boucle, votre code risque d'être plus difficile à lire et à déboguer. Changer la valeur de start, end ou step n'affecte pas les valeurs d'itération déterminées lors de la première entrée de la boucle.

Ainsi, la valeur de To 10 - stringValue.Length est évaluée une fois et réutilisée jusqu'à la sortie des boucles.

Cependant, regardez c # pour l'instruction

Si for_condition n'est pas présent ou si l'évaluation donne true, le contrôle est transféré à l'instruction incorporée. Quand et si le contrôle atteint le point final de l'instruction incorporée (éventuellement à partir de l'exécution d'une instruction continue), les expressions du for_iterator, le cas échéant, sont évaluées dans l'ordre, puis une autre itération est effectuée, en commençant par l'évaluation. du for_condition dans l'étape ci-dessus.

Ce qui signifie fondamentalement que la condition ; i <= 10 - stringValueLength; est à nouveau évaluée à chaque fois.

Ainsi, comme vous l'avez vu, si vous souhaitez reproduire le code, vous devez déclarer le compteur final en c # avant de lancer la boucle.

22

Afin de rendre l'exemple plus compréhensible, je vais convertir les deux boucles en C # en boucle .

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++;
}

La différence est alors:

VB.NET met en cache la valeur maximale de i, mais C # la recalcule à chaque fois.

10
Maxime Recuerda

Parce que la for dans VB est une sémantique différente de la for dans C # (ou tout autre langage de type C)

En VB, l'instruction for incrémente spécifiquement un compteur d'une valeur à une autre.

En C, C++, C #, etc., l'instruction for évalue simplement trois expressions:

  • La première expression est habituellement une initialisation
  • La deuxième expression est évaluée au début de chaque itération pour déterminer si la condition de terminal est remplie.
  • La troisième expression est évaluée à la fin de chaque itération, qui est habituellement un incrémenteur.

En VB, vous devez fournir une variable numérique qui peut être testée par rapport à une valeur terminale et incrémentée à chaque itération

En C, C++, C #, etc., les trois expressions sont contraintes au minimum. l'expression conditionnelle doit avoir la valeur true/false (ou un entier égal à zéro/non nul en C, C++). Vous n'avez pas du tout besoin d'effectuer une initialisation, vous pouvez itérer n'importe quel type sur une plage de valeurs, un pointeur ou une référence sur une structure complexe, ou ne rien itérer du tout.

Ainsi, en C #, etc., l'expression de condition doit être entièrement évaluée à chaque itération, mais en VB, la valeur terminale de l'itérateur doit être évaluée au début et n'a pas besoin d'être évaluée à nouveau.

7
C Robinson