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

87

Je suis en train de migrer un projet de Visual Basic vers C # et j'ai dû changer la façon dont une forboucle utilisée est déclarée.

Dans VB.NET, la forboucle 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 forboucle 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

Ce n'est évidemment pas correct, j'ai donc dû modifier légèrement le code et j'ai inclus 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 en quoi Visual Basic diffère de C # en termes de Visual Basic en utilisant la stringValue.Lengthcondition dans la forboucle même si chaque fois que la boucle se produit, la longueur de la chaîne change. Alors que dans C # si j'utilise la stringValue.Lengthdans la forcondition de la boucle , il modifie la valeur de chaîne initiale chaque fois que la boucle se produit. Pourquoi est-ce?

slee423
la source
7
Microsoft décrit clairement quel est votre problème ...
Codexer
39
@ Çöđěxěŕ: Arrêtez, s'il vous plaît. Si la suppression robotique des balises du titre sans tenir compte du contexte était utile, le site Web le ferait.
Ry-
11
@ Çöđěxěŕ Vous pouvez trouver des informations à ce sujet ici
pushkin
35
@ Çöđěxěŕ Je ne pense pas que les deux messages se contredisent. Le point est: ne collez pas maladroitement une balise dans le titre comme "question sur cette chose - balise". Mais si le titre est une phrase complète qui inclut la balise, alors c'est parfois correct. «Pourquoi la boucle for se comporte-t-elle différemment lors de la migration» semble être un titre bien trop générique.
pushkin
26
@ Çöđěxěŕ "migrer le code VB.NET vers C #" est clairement une phrase complète qui ajoute des informations utiles au titre. N'apportez pas de modifications qui réduisent la clarté. Espérons que cette notion est suffisamment logique pour que nous n'ayons pas besoin d'un message Meta pour la sauvegarder.
jpmc26

Réponses:

115

En C #, la condition aux limites de la boucle est évaluée à chaque itération. Dans VB.NET, il n'est évalué qu'à l'entrée dans la boucle.

Ainsi, dans la version C # de la question, comme la longueur de stringValueest modifiée dans la boucle, la valeur finale de la variable de boucle sera modifiée.

Dans VB.NET, la condition finale est inclusive, vous utiliseriez donc à la <=place de <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 doit être calculée une seule fois avant la boucle.

Andrew Morton
la source
Merci pour la réponse. Je me rends compte maintenant que l'utilisation <=me permet d'itérer et d'avoir la même sortie que le code VB. Cependant, je suis plus intéressé de savoir pourquoi j'ai dû déclarer la variable entière et VBje n'ai pas eu à le faire. Je vais mettre à jour ma question pour afficher la même sortie.
slee423
@ slee423 La raison est donnée dans la première phrase de ma réponse. Étant donné que la longueur de stringValueest modifiée dans la boucle, la valeur finale de la variable de boucle sera modifiée.
Andrew Morton
1
excuses, merci pour cette réponse. Et merci de l'avoir élaboré plus en détail pour moi.
slee423
1
@ slee423 J'ai ajouté cela dans la réponse car cela la clarifie effectivement.
Andrew Morton
22

Maintenant, ma question porte sur la façon dont VB diffère de C # en termes de VB en utilisant la condition stringValue.Length dans la boucle for, même si chaque fois que la boucle se produit, la longueur de la chaîne change.

Selon la documentation VB.NET :

Si vous modifiez la valeur de counterwhile à l'intérieur d'une boucle, votre code peut être plus difficile à lire et à déboguer. La modification de la valeur de start, endou stepn'affecte pas les valeurs d'itération qui ont été déterminées lors de la première entrée de la boucle.

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

Cependant, regardez l' instruction for c #

Si le for_conditionn'est pas présent ou si l'évaluation aboutit true, le contrôle est transféré à l'instruction incorporée. Quand et si le contrôle atteint le point de fin de l'instruction incorporée (éventuellement à partir de l'exécution d'une instruction continue), les expressions de for_iterator, le cas échéant, sont évaluées en séquence, puis une autre itération est effectuée, en commençant par l'évaluation du for_conditiondans l'étape au dessus.

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

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

Camilo Terevinto
la source
11

Afin de rendre l'exemple plus compréhensible, je convertir à la fois pour les boucles en C # en boucles .

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.

Maxime Recuerda
la source
2
Vous n'avez pas besoin de convertir les boucles en while
Panagiotis Kanavos
10
Cela m'a aidé à comprendre le for loopsà mes débuts, je pense qu'ils sont beaucoup plus compréhensibles. C'est pourquoi j'ai «traduit» les exemples dans while loops, pour aider à comprendre.
Maxime Recuerda
7

Parce que le forin VB est une sémantique différente du forin C # (ou de tout autre langage de type C)

Dans VB, l' forinstruction incrémente spécifiquement un compteur d'une valeur à une autre.

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

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

Dans 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 être évaluée à un vrai / faux (ou un entier zéro / différent de zéro en C, C ++). Vous n'avez pas du tout besoin d'effectuer une initialisation, vous pouvez itérer n'importe quel type sur n'importe quelle plage de valeurs, itérer 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.

C Robinson
la source