Los he visto tanto que se utilizan en numerosos trozos de código C #, y me gustaría saber cuándo usar i++o ++i( isiendo una variable igual número int, float, double, etc). ¿Alguien que sepa esto?
Los he visto tanto que se utilizan en numerosos trozos de código C #, y me gustaría saber cuándo usar i++o ++i( isiendo una variable igual número int, float, double, etc). ¿Alguien que sepa esto?
Respuestas:
Curiosamente parece que las otras dos respuestas no lo explican, y definitivamente vale la pena decir:
i++significa 'dime el valor de i, luego incrementa'
++isignifica 'incrementar i, entonces dime el valor'
Son operadores de pre-incremento, post-incremento. En ambos casos, la variable se incrementa , pero si tuviera que tomar el valor de ambas expresiones exactamente en los mismos casos, el resultado sería diferente.
La respuesta típica a esta pregunta, desafortunadamente publicada aquí, es que uno hace el incremento "antes" de las operaciones restantes y el otro hace el incremento "después" de las operaciones restantes. Aunque eso intuitivamente transmite la idea, esa afirmación es completamente incorrecta . La secuencia de eventos en el tiempo está extremadamente bien definida en C #, y enfáticamente no el caso que las versiones de prefijo (++ var) y postfix (var ++) de ++ hagan las cosas en un orden diferente con respecto a otras operaciones.
No es sorprendente que vea muchas respuestas incorrectas a esta pregunta. Una gran cantidad de libros de "autodidacta C #" también se equivocan. Además, la forma en que C # lo hace es diferente de cómo lo hace C. Mucha gente razona como si C # y C fueran el mismo lenguaje; ellos no son. El diseño de los operadores de incremento y decremento en C # en mi opinión evita las fallas de diseño de estos operadores en C.
Hay dos preguntas que deben responderse para determinar cuál es exactamente la operación de prefijo y postfix ++ en C #. La primera pregunta es ¿cuál es el resultado? y la segunda pregunta es ¿ cuándo tiene lugar el efecto secundario del incremento?
No es obvio cuál es la respuesta a cualquiera de las preguntas, pero en realidad es bastante simple una vez que la ve. Permíteme explicarte con precisión qué hacen x ++ y ++ x para una variable x.
Para la forma del prefijo (++ x):
Para el formulario de postfix (x ++):
Algunas cosas para notar:
Primero, el orden de los eventos en el tiempo es exactamente el mismo en ambos casos . Una vez más, es absolutamente no el caso de que el orden de los acontecimientos en el tiempo cambia entre el prefijo y de sufijo. Es completamente falso decir que la evaluación ocurre antes de otras evaluaciones o después de otras evaluaciones. Las evaluaciones suceden exactamente en el mismo orden en ambos casos, como puede ver en los pasos 1 a 4 que son idénticos. La única diferencia es el último paso. : si el resultado es el valor del valor incremental temporal o el nuevo.
Puede demostrar esto fácilmente con una sencilla aplicación de consola C #:
public class Application
{
public static int currentValue = 0;
public static void Main()
{
Console.WriteLine("Test 1: ++x");
(++currentValue).TestMethod();
Console.WriteLine("\nTest 2: x++");
(currentValue++).TestMethod();
Console.WriteLine("\nTest 3: ++x");
(++currentValue).TestMethod();
Console.ReadKey();
}
}
public static class ExtensionMethods
{
public static void TestMethod(this int passedInValue)
{
Console.WriteLine("Current:{0} Passed-in:{1}",
Application.currentValue,
passedInValue);
}
}
Aquí están los resultados...
Test 1: ++x
Current:1 Passed-in:1
Test 2: x++
Current:2 Passed-in:1
Test 3: ++x
Current:3 Passed-in:3
En la primera prueba, puede ver que ambos currentValuey lo que se pasó aTestMethod() extensión muestran el mismo valor, como se esperaba.
Sin embargo, en el segundo caso, las personas tratarán de decirle que el incremento de currentValueocurre después de la llamada a TestMethod(), pero como puede ver en los resultados, sucede antes de la llamada como lo indica el resultado 'Actual: 2'.
En este caso, primero el valor de currentValuese almacena en un temporal. A continuación, una versión incrementada de ese valor se almacena de nuevo currentValuepero sin tocar el temporal que aún almacena el valor original. Finalmente ese temporal se pasa a TestMethod(). Si el incremento ocurrió después de la llamada aTestMethod() entonces escribiría el mismo valor no incrementado dos veces, pero no es así.
Es importante tener en cuenta que el valor devuelto por ambos
currentValue++y++currentValueoperaciones se basa en el valor temporal y no en el valor real almacenado en la variable en el momento en que sale cualquiera de las operaciones.Recuerde en el orden de las operaciones anteriores, los dos primeros pasos copian el valor actual de la variable en el temporal. Eso es lo que se usa para calcular el valor de retorno; en el caso de la versión de prefijo, es ese valor temporal incrementado, mientras que en el caso de la versión de sufijo, es ese valor directamente / no incrementado. La variable en sí misma no se vuelve a leer después del almacenamiento inicial en el temporal.
En pocas palabras, la versión de postfix devuelve el valor que se leyó de la variable (es decir, el valor de lo temporal) mientras que la versión de prefijo devuelve el valor que se volvió a escribir en la variable (es decir, el valor incrementado de lo temporal). Tampoco devuelve el valor de la variable.
Esto es importante de entender porque la variable en sí misma podría ser volátil y haber cambiado en otro subproceso, lo que significa que el valor de retorno de esas operaciones podría diferir del valor actual almacenado en la variable.
Es sorprendentemente común que las personas se confundan mucho sobre la precedencia, la asociatividad y el orden en que se ejecutan los efectos secundarios, sospecho principalmente porque es muy confuso en C. C # ha sido cuidadosamente diseñado para ser menos confuso en todos estos aspectos. Para un análisis adicional de estos problemas, incluyéndome para demostrar aún más la falsedad de la idea de que las operaciones de prefijos y postfijos "mueven cosas a tiempo", vea:
https://ericlippert.com/2009/08/10/precedence-vs-order-redux/
lo que llevó a esta pregunta SO:
int [] arr = {0}; valor int = arr [arr [0] ++]; Valor = 1?
También te pueden interesar mis artículos anteriores sobre el tema:
https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/
y
https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/
y un caso interesante en el que C dificulta razonar sobre la corrección:
https://docs.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited
Además, nos encontramos con problemas sutiles similares al considerar otras operaciones que tienen efectos secundarios, como asignaciones simples encadenadas:
https://docs.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple
Y aquí hay una publicación interesante sobre por qué los operadores de incremento resultan en valores en C # en lugar de en variables :
i++o ++ise usan en código, las cosas que están sucediendo en segundo plano son solo eso; en el fondo . Escribo C # para subir a niveles de abstracción por encima de lo que está sucediendo en este nivel, por lo que si esto realmente importa para su código C #, es posible que ya esté en el lenguaje incorrecto.
i++;) está en for (int i = 0; i < x; i++)... Y estoy muy muy feliz de esto! (y nunca uso el operador de prefijo). Si tengo que escribir algo que requerirá que un programador senior descifre 2 minutos ... Bueno ... Es mejor escribir una línea más de código o introducir una variable temporal :-) Creo que su "artículo" (gané no lo llamo "respuesta") reivindica mi elección :-)
Si usted tiene:
int i = 10;
int x = ++i;
entonces xserá 11.
Pero si tienes:
int i = 10;
int x = i++;
entonces xserá 10.
Tenga en cuenta que, como señala Eric, el incremento se produce al mismo tiempo en ambos casos, pero es el valor que se da como resultado lo que difiere (¡gracias Eric!).
En general, me gusta usar a ++imenos que haya una buena razón para no hacerlo. Por ejemplo, cuando escribo un bucle, me gusta usar:
for (int i = 0; i < 10; ++i) {
}
O, si solo necesito incrementar una variable, me gusta usar:
++x;
Normalmente, de una forma u otra no tiene mucha importancia y se reduce al estilo de codificación, pero si está utilizando los operadores dentro de otras tareas (como en mis ejemplos originales), es importante tener en cuenta los posibles efectos secundarios.
ipara el nombre de la variable en lugar de varcomo es una palabra clave de C #.
int i = 0;
Console.WriteLine(i++); // Prints 0. Then value of "i" becomes 1.
Console.WriteLine(--i); // Value of "i" becomes 0. Then prints 0.
¿Responde esto a tu pregunta?
La forma en que funciona el operador es que se incrementa al mismo tiempo, pero si está antes de una variable, la expresión se evaluará con la variable incrementada / decrementada:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
Si es posterior a la variable, la instrucción actual se ejecutará con la variable original, como si aún no se hubiera incrementado / decrementado:
int x = 0; //x is 0
int y = x++; //'y = x' is evaluated with x=0, but x is still incremented. So, x is 1, but y is 0
Estoy de acuerdo con dcp en el uso de pre-incremento / decremento (++ x) a menos que sea necesario. Realmente, la única vez que uso el incremento / decremento posterior es en bucles while o bucles de ese tipo. Estos bucles son iguales:
while (x < 5) //evaluates conditional statement
{
//some code
++x; //increments x
}
o
while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
//some code
}
También puede hacer esto mientras indexa matrices y demás:
int i = 0;
int[] MyArray = new int[2];
MyArray[i++] = 1234; //sets array at index 0 to '1234' and i is incremented
MyArray[i] = 5678; //sets array at index 1 to '5678'
int temp = MyArray[--i]; //temp is 1234 (becasue of pre-decrement);
Etcétera etcétera...
Solo para el registro, en C ++, si puede usar cualquiera de ellos (es decir, no le importa el orden de las operaciones (solo desea aumentar o disminuir y usarlo más adelante), el operador de prefijo es más eficiente ya que no tiene que crear una copia temporal del objeto. Desafortunadamente, la mayoría de las personas usan posfix (var ++) en lugar de prefijo (++ var), solo porque eso es lo que aprendimos inicialmente. (Me preguntaron sobre esto en una entrevista). No estoy seguro de si esto es cierto en C #, pero supongo que lo sería.