Eu vi os dois sendo usado em inúmeras peças de código C #, e eu gostaria de saber quando usar i++ou ++i( isendo uma variável número como int, float, double, etc). Alguém que sabe disso?
Eu vi os dois sendo usado em inúmeras peças de código C #, e eu gostaria de saber quando usar i++ou ++i( isendo uma variável número como int, float, double, etc). Alguém que sabe disso?
Respostas:
Estranhamente, parece que as outras duas respostas não explicam bem, e definitivamente vale a pena dizer:
i++significa "diga-me o valor de ie depois aumente"
++isignifica "incremento i, então me diga o valor"
Eles são operadores de pré-incremento e pós-incremento. Nos dois casos, a variável é incrementada , mas se você pegar o valor de ambas as expressões exatamente nos mesmos casos, o resultado será diferente.
A resposta típica para esta pergunta, infelizmente já postada aqui, é que um faz o incremento "antes" das operações restantes e o outro faz o incremento "depois" das operações restantes. Embora intuitivamente transmita a ideia, essa afirmação está completamente errada . A sequência de eventos no tempo é extremamente bem definida em C # e enfaticamente não é o caso de as versões prefixo (++ var) e postfix (var ++) do ++ fazerem coisas em uma ordem diferente em relação a outras operações.
Não é de surpreender que você veja muitas respostas erradas para essa pergunta. Muitos livros "ensine a si mesmo C #" também entendem errado. Além disso, a maneira como o C # faz isso é diferente da maneira como o faz. Muitas pessoas raciocinam como se C # e C fossem a mesma linguagem; eles não são. O design dos operadores de incremento e decremento em C #, na minha opinião, evita as falhas de design desses operadores em C.
Há duas perguntas que devem ser respondidas para determinar qual é exatamente a operação do prefixo e do postfix ++ em C #. A primeira pergunta é qual é o resultado? e a segunda pergunta é quando ocorre o efeito colateral do incremento?
Não é óbvio qual é a resposta para qualquer uma das perguntas, mas na verdade é bastante simples quando você a vê. Deixe-me explicar exatamente o que x ++ e ++ x fazem por uma variável x.
Para o formato do prefixo (++ x):
Para o formulário postfix (x ++):
Algumas coisas a serem observadas:
Primeiro, a ordem dos eventos no tempo é exatamente a mesma nos dois casos . Mais uma vez, é absolutamente não o caso que a ordem dos eventos em tempo muda entre prefixo e postfix. É totalmente falso dizer que a avaliação ocorre antes de outras avaliações ou após outras avaliações. As avaliações ocorrem exatamente na mesma ordem nos dois casos, como você pode ver pelas etapas 1 a 4 sendo idênticas. A única diferença é o último passo - se o resultado é o valor do valor incrementado temporário ou novo.
Você pode demonstrar isso facilmente com um simples aplicativo de console em 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);
}
}
Aqui estão os 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
No primeiro teste, você pode ver que ambos currentValuee o que foi passado para oTestMethod() extensão mostram o mesmo valor, conforme o esperado.
No entanto, no segundo caso, as pessoas tentarão dizer que o incremento de currentValueacontece após a chamada para TestMethod(), mas, como você pode ver nos resultados, ocorre antes da chamada, conforme indicado pelo resultado 'Atual: 2'.
Nesse caso, primeiro o valor de currentValueé armazenado temporariamente. Em seguida, uma versão incrementada desse valor é armazenada novamente, currentValuemas sem tocar no temporário, que ainda armazena o valor original. Finalmente, esse temporário é passado para TestMethod(). Se o incremento ocorreu após a chamada TestMethod(), ele gravaria o mesmo valor não incrementado duas vezes, mas não o faria.
É importante observar que o valor retornado das operações
currentValue++e++currentValueé baseado no valor temporário e não no valor real armazenado na variável no momento em que a operação termina.Lembre-se da ordem das operações acima, as duas primeiras etapas copiam o valor atual da variável no temporário. É isso que é usado para calcular o valor de retorno; no caso da versão do prefixo, é esse valor temporário incrementado, enquanto no caso da versão do sufixo, é esse valor diretamente / não incrementado. A variável em si não é lida novamente após o armazenamento inicial no temporário.
Em termos mais simples, a versão do postfix retorna o valor que foi lido da variável (ou seja, o valor do temporário) enquanto a versão do prefixo retorna o valor que foi gravado de volta na variável (ou seja, o valor incrementado do temporário). Nem retorne o valor da variável.
Isso é importante para entender porque a variável em si pode ser volátil e mudou em outro encadeamento, o que significa que o valor de retorno dessas operações pode diferir do valor atual armazenado na variável.
É surpreendentemente comum as pessoas ficarem muito confusas sobre precedência, associatividade e a ordem em que os efeitos colaterais são executados, suspeito, principalmente porque é tão confuso em C. O C # foi cuidadosamente projetado para ser menos confuso em todos esses aspectos. Para algumas análises adicionais desses problemas, inclusive eu demonstrando ainda mais a falsidade da ideia de que operações de prefixo e postfix "movimentam as coisas no tempo", consulte:
https://ericlippert.com/2009/08/10/precedence-vs-order-redux/
o que levou a essa pergunta do SO:
int [] arr = {0}; valor int = arr [arr [0] ++]; Valor = 1?
Você também pode estar interessado nos meus artigos anteriores sobre o assunto:
https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/
e
https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/
e um caso interessante em que C dificulta a argumentação sobre a correção:
https://docs.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited
Além disso, encontramos problemas sutis semelhantes ao considerar outras operações com efeitos colaterais, como atribuições simples encadeadas:
https://docs.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple
E aqui está um post interessante sobre por que os operadores de incremento resultam em valores em C # e não em variáveis :
Por que não consigo fazer o ++ i ++ em linguagens do tipo C?
i++ou ++ié usado em código, as coisas acontecendo em segundo plano são exatamente isso; em segundo plano . Eu escrevo C # para subir para níveis de abstração acima do que está acontecendo nesse nível; portanto, se isso realmente importa para o seu código C #, você já deve estar no idioma errado.
i++;está) está em for (int i = 0; i < x; i++)... E eu sou muito, muito feliz por isso! (e eu nunca uso o operador prefixo). Se eu tiver que escrever algo que exija um programador sênior 2 minutos para decifrar ... Bem ... É melhor escrever mais uma linha de código ou introduzir uma variável temporária :-) Acho que o seu "artigo" (ganhei 't chamá-lo de 'resposta') reivindica a minha escolha :-)
Se você tem:
int i = 10;
int x = ++i;
então xserá 11.
Mas se você tiver:
int i = 10;
int x = i++;
então xserá 10.
Observe como Eric aponta, o incremento ocorre ao mesmo tempo em ambos os casos, mas é o valor que é dado como resultado diferente (obrigado Eric!).
Geralmente, eu gosto de usar, a ++imenos que haja uma boa razão para não usar . Por exemplo, ao escrever um loop, eu gosto de usar:
for (int i = 0; i < 10; ++i) {
}
Ou, se eu apenas precisar incrementar uma variável, gosto de usar:
++x;
Normalmente, de uma maneira ou de outra, não tem muito significado e se resume ao estilo de codificação, mas se você estiver usando os operadores em outras atribuições (como nos meus exemplos originais), é importante estar ciente dos possíveis efeitos colaterais.
ino nome da variável, e não varcomo uma palavra-chave em C #.
A maneira como o operador trabalha é que ele é incrementado ao mesmo tempo, mas se for antes de uma variável, a expressão será avaliada com a variável incrementada / decrementada:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
Se for após a variável, a instrução atual será executada com a variável original, como se ainda não tivesse sido incrementada / decrementada:
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
Concordo com o dcp no uso de pré-incremento / decremento (++ x), a menos que seja necessário. Realmente, a única vez em que uso o pós-incremento / decremento é enquanto loops ou loops desse tipo. Esses loops são os mesmos:
while (x < 5) //evaluates conditional statement
{
//some code
++x; //increments x
}
ou
while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
//some code
}
Você também pode fazer isso ao indexar matrizes e coisas como:
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 etc...
Apenas para o registro, em C ++, se você pode usar (ou seja), não se importa com a ordem das operações (você só deseja aumentar ou diminuir e usá-lo mais tarde), o operador de prefixo é mais eficiente, pois não precisa criar uma cópia temporária do objeto. Infelizmente, a maioria das pessoas usa o posfix (var ++) em vez do prefixo (++ var), apenas porque foi o que aprendemos inicialmente. (Fui perguntado sobre isso em uma entrevista). Não tenho certeza se isso é verdade em c #, mas presumo que seria.