¿Por qué un bucle for se comporta de manera diferente al migrar el código VB.NET a C #?

87

Estoy en el proceso de migrar un proyecto de Visual Basic a C # y tuve que cambiar la forma en forque se declara un bucle.

En VB.NET, el forbucle se declara a continuación:

Dim stringValue As String = "42"

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

Qué salidas:

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 #, el forbucle se declara a continuación:

string stringValue = "42";

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

Y la salida:

42 1
42 1 2
42 1 2 3

Obviamente, esto no es correcto, así que tuve que cambiar el código ligeramente e incluí una variable entera que mantendría la longitud de la cadena.

Consulte el código a continuación:

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

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

Y la salida:

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

Ahora mi pregunta se resuelve en torno a cómo Visual Basic difiere de C # en términos de Visual Basic usando la stringValue.Lengthcondición en el forbucle, aunque cada vez que ocurre el bucle cambia la longitud de la cadena. Mientras que en C # si uso la condición stringValue.Lengthen el forbucle, cambia el valor de la cadena inicial cada vez que ocurre el bucle. ¿Por qué es esto?

slee423
fuente
7
Microsoft describe claramente cuál es su problema ...
Çöđěxěŕ
39
@ Çöđěxěŕ: Detente, por favor. Si la eliminación robótica de etiquetas del título sin tener en cuenta el contexto fuera útil, el sitio web lo haría.
Ry-
11
@ Çöđěxěŕ Puedes encontrar información sobre eso aquí
pushkin
35
@ Çöđěxěŕ No creo que las dos publicaciones se contradigan. El punto es: no pegue incómodamente una etiqueta en el título como "pregunta sobre esto - etiqueta". Pero si el título es una oración completa que incluye la etiqueta, a veces está bien. "¿Por qué el bucle for se comporta de manera diferente cuando se migra?" Parece un título demasiado genérico.
Pushkin
26
@ Çöđěxěŕ "migrar código VB.NET a C #" es claramente una frase completa que agrega información útil al título. No realice ediciones que disminuyan la claridad. Con suerte, esa noción es lo suficientemente de sentido común como para que no necesitemos una publicación de Meta para respaldarla.
jpmc26

Respuestas:

115

En C #, la condición de límite de bucle se evalúa en cada iteración. En VB.NET, solo se evalúa al ingresar al ciclo.

Entonces, en la versión C # de la pregunta, debido a que la longitud de stringValuese está cambiando en el ciclo, se cambiará el valor de la variable del ciclo final.

En VB.NET, la condición final es inclusiva, por lo que usaría en <=lugar de <en C #.

La evaluación de la condición final en C # tiene el corolario de que incluso si no varía pero es costoso de calcular, debe calcularse solo una vez antes del ciclo.

Andrew Morton
fuente
Gracias por la respuesta. Ahora me doy cuenta de que el uso <=me permite iterar y tener el mismo resultado que el código VB. Sin embargo, estoy más interesado en saber por qué tuve que declarar la variable entera y VBno tuve que hacerlo. Actualizaré mi pregunta para mostrar el mismo resultado.
slee423
@ slee423 La razón se da en la primera oración de mi respuesta. Debido a que la longitud de stringValuese está cambiando en el ciclo, se cambiará el valor final de la variable del ciclo.
Andrew Morton
1
disculpas, gracias por esa respuesta. Y gracias por elaborarlo con más detalle para mí.
slee423
1
@ slee423 Agregué eso en la respuesta, ya que de hecho lo aclara.
Andrew Morton
22

Ahora mi pregunta se resuelve en torno a cómo VB difiere de C # en términos de VB usando la condición stringValue.Length en el bucle for, aunque cada vez que ocurre el bucle, la longitud de la cadena cambia.

Según la documentación de VB.NET :

Si cambia el valor de counterwhile dentro de un bucle, su código puede ser más difícil de leer y depurar. Cambiar el valor de start, endo stepno afecta los valores de iteración que se determinaron cuando se ingresó el bucle por primera vez.

Por lo tanto, el valor de To 10 - stringValue.Lengthse evalúa una vez y se reutiliza hasta que salen los bucles.

Sin embargo, mire c # para la declaración

Si for_conditionno está presente o si la evaluación cede true, el control se transfiere a la declaración incorporada. Cuando y si el control alcanza el punto final de la instrucción incorporada (posiblemente a partir de la ejecución de una instrucción continue), las expresiones de for_iterator, si las hay, se evalúan en secuencia, y luego se realiza otra iteración, comenzando con la evaluación de for_conditionen el paso encima.

Lo que básicamente significa que la condición ; i <= 10 - stringValueLength;se evalúa nuevamente cada vez.

Entonces, como vio, si desea replicar el código, debe declarar el contador final en c # antes de comenzar el ciclo.

Camilo Terevinto
fuente
11

Con el fin de hacer más comprensible el ejemplo, voy a convertir tanto para los bucles en C # , mientras que los bucles .

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 diferencia es entonces:

VB.NET almacena en caché el valor máximo de i, pero C # lo vuelve a calcular cada vez.

Maxime Recuerda
fuente
2
No es necesario convertir bucles a while
Panagiotis Kanavos
10
Me ayudó a entender los for loopsprimeros, creo que son mucho más comprensibles. Es por eso que "traduje" los ejemplos while loopspara ayudar a comprender.
Maxime Recuerda
7

Porque foren VB es una semántica diferente a foren C # (o cualquier otro lenguaje similar a C)

En VB, la fordeclaración está incrementando específicamente un contador de un valor a otro.

En C, C ++, C #, etc., la fordeclaración simplemente evalúa tres expresiones:

  • La primera expresión es habitualmente una inicialización
  • La segunda expresión se evalúa al comienzo de cada iteración para determinar si se ha cumplido la condición terminal.
  • La tercera expresión se evalúa al final de cada iteración, que habitualmente es un incrementador.

En VB, debe proporcionar una variable numérica que pueda probarse con un valor terminal e incrementarse en cada iteración

En C, C ++, C #, etc., las tres expresiones están mínimamente restringidas; la expresión condicional debe evaluarse como verdadero / falso (o entero cero / distinto de cero en C, C ++). No necesita realizar una inicialización en absoluto, puede iterar cualquier tipo sobre cualquier rango de valores, iterar un puntero o referencia sobre una estructura compleja o no iterar nada en absoluto.

Entonces, en C #, etc., la expresión de la condición debe evaluarse completamente en cada iteración, pero en VB, el valor terminal del iterador debe evaluarse al principio y no es necesario evaluarlo nuevamente.

C Robinson
fuente