Я видел их обоих используются в многочисленных кусков кода С #, и я хотел бы знать , когда использовать i++или ++i( iбудучи переменным числом , как int, float, doubleи т.д.). Кто-нибудь, кто знает это?
Я видел их обоих используются в многочисленных кусков кода С #, и я хотел бы знать , когда использовать i++или ++i( iбудучи переменным числом , как int, float, doubleи т.д.). Кто-нибудь, кто знает это?
Ответы:
Как ни странно, остальные два ответа ничего не объясняют, и определенно стоит сказать:
i++означает «скажи мне значение i, а затем увеличить»
++iозначает «приращение i, а затем скажите мне значение»
Это операторы перед инкрементом, постинкрементные. В обоих случаях переменная увеличивается , но если вы берете значение обоих выражений в одинаковых случаях, результат будет отличаться.
Типичный ответ на этот вопрос, к сожалению, уже опубликованный здесь, заключается в том, что один выполняет приращение «до» оставшихся операций, а другой - «после» оставшихся операций. Хотя это интуитивно передает идею, это утверждение на первый взгляд совершенно неверно . Последовательность событий во время очень хорошо определена в C #, и это решительно не тот случай, когда префикс (++ вара) и постфикс (вар ++) версия ++ делать вещи в другом порядке по отношению к другим операциям.
Неудивительно, что вы увидите много неправильных ответов на этот вопрос. Огромное количество книг "научи себя C #" также ошибаются. Кроме того, способ, которым C # делает это, отличается от того, как это делает C. Многие люди считают, что C # и C - это один и тот же язык; они не. Конструкция операторов приращения и убывания в C #, на мой взгляд, позволяет избежать конструктивных недостатков этих операторов в C.
Есть два вопроса, на которые нужно ответить, чтобы определить, что именно происходит с префиксом и постфиксом ++ в C #. Первый вопрос: каков результат? и второй вопрос: когда происходит побочный эффект приращения?
Не ясно, каков ответ на любой вопрос, но на самом деле все довольно просто, когда вы его видите. Позвольте мне объяснить вам, что именно x ++ и ++ x делают для переменной x.
Для префиксной формы (++ x):
Для формы постфикса (x ++):
Некоторые вещи, на которые стоит обратить внимание:
Во-первых, порядок событий во времени одинаков в обоих случаях . Опять же, это абсолютно не тот случай, когда порядок событий во времени изменяется между префиксом и постфиксом. Совершенно неверно говорить, что оценка происходит до других оценок или после других оценок. Оценки выполняются в одном и том же порядке в обоих случаях, как можно видеть на шагах с 1 по 4, которые идентичны. Лишь отличием является последним шагом - будь то результатом является значение временного или нового, увеличивающегося значения.
Вы можете легко продемонстрировать это с помощью простого консольного приложения 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);
}
}
Вот результаты ...
Test 1: ++x
Current:1 Passed-in:1
Test 2: x++
Current:2 Passed-in:1
Test 3: ++x
Current:3 Passed-in:3
В первом тесте вы можете увидеть, что currentValueи то, что было переданоTestMethod() расширению, показывают одинаковое значение, как и ожидалось.
Однако во втором случае люди попытаются сообщить вам, что приращение currentValueпроисходит после вызова TestMethod(), но, как вы можете видеть из результатов, это происходит до вызова, как указано в результате «Текущий: 2».
В этом случае сначала значение currentValueсохраняется во временном. Затем инкрементная версия этого значения сохраняется обратно, currentValueно без касания временного, в котором все еще сохраняется исходное значение. Наконец то временное передается TestMethod(). Если инкремент произошел после вызова, TestMethod()он дважды вывел бы одно и то же, не приращенное значение, но это не так.
Важно отметить, что значение, возвращаемое как из операций, так
currentValue++и из++currentValueопераций, основано на временном, а не фактическом значении, сохраненном в переменной в момент выхода из любой операции.Напомним, что в порядке операций выше, первые два шага копируют текущее значение переменной во временное. Это то, что используется для расчета возвращаемого значения; в случае версии с префиксом это временное значение увеличивается, а в случае версии с суффиксом это значение напрямую / не увеличивается. Сама переменная не читается снова после первоначального хранения во временную.
Проще говоря, постфиксная версия возвращает значение, которое было прочитано из переменной (т. Е. Значение временного), в то время как префиксная версия возвращает значение, которое было записано обратно в переменную (т. Е. Увеличенное значение временного). Ни один из них не возвращает значение переменной.
Это важно понимать, поскольку сама переменная может быть изменчивой и изменяться в другом потоке, что означает, что возвращаемое значение этих операций может отличаться от текущего значения, хранящегося в переменной.
Люди на удивление часто запутываются в отношении приоритета, ассоциативности и порядка выполнения побочных эффектов, я подозреваю, что в основном потому, что это так запутанно в C. C # был тщательно спроектирован, чтобы быть менее запутанным во всех этих отношениях. Для некоторого дополнительного анализа этих проблем, включая мою дальнейшую демонстрацию ложности идеи о том, что префиксные и постфиксные операции «перемещают вещи во времени», смотрите:
https://ericlippert.com/2009/08/10/precedence-vs-order-redux/
что привело к такому вопросу:
int [] arr = {0}; int value = arr [arr [0] ++]; Значение = 1?
Вас также могут заинтересовать мои предыдущие статьи на эту тему:
https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/
и
https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/
и интересный случай, когда C затрудняет рассуждения о правильности:
https://docs.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited
Кроме того, мы сталкиваемся с похожими тонкими проблемами при рассмотрении других операций, которые имеют побочные эффекты, такие как цепочка простых назначений:
https://docs.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple
И вот интересный пост о том, почему операторы приращения приводят к значениям в C #, а не в переменных :
i++или ++iиспользуется в коде, вещи, происходящие в фоновом режиме, просто так; на заднем плане . Я пишу на C #, чтобы подняться на уровни абстракции выше того, что происходит на этом уровне, поэтому, если это действительно имеет значение для вашего кода C #, возможно, вы уже не на том языке.
i++;) for (int i = 0; i < x; i++)... И я очень очень рад этому! (и я никогда не использую префиксный оператор). Если мне нужно написать что-то, что понадобится старшему программисту за 2 минуты, чтобы расшифровать ... Ну ... Лучше написать еще одну строку кода или ввести временную переменную :-) Я думаю, что ваша "статья" (я выиграл не называйте это «ответ») подтверждает мой выбор :-)
Если у вас есть:
int i = 10;
int x = ++i;
тогда xбудет 11.
Но если у вас есть:
int i = 10;
int x = i++;
тогда xбудет 10.
Обратите внимание, как указывает Эрик, приращение происходит одновременно в обоих случаях, но это то, какое значение дается как результат, который отличается (спасибо, Эрик!).
Обычно я люблю использовать, ++iесли нет веских причин не делать этого. Например, при написании цикла мне нравится использовать:
for (int i = 0; i < 10; ++i) {
}
Или, если мне просто нужно увеличить переменную, я хотел бы использовать:
++x;
Обычно, так или иначе, не имеет большого значения и сводится к стилю кодирования, но если вы используете операторы внутри других назначений (как в моих исходных примерах), важно знать о потенциальных побочных эффектах.
iдля имени переменной, а не varкак ключевое слово 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.
Отвечает ли это на ваш вопрос ?
Оператор работает так, что он увеличивается в одно и то же время, но если он находится перед переменной, выражение будет оцениваться с помощью увеличенной / уменьшенной переменной:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
Если это после переменной, текущий оператор будет выполнен с исходной переменной, как если бы он еще не был увеличен / уменьшен:
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
Я согласен с dcp в использовании предварительного увеличения / уменьшения (++ x) без необходимости. Действительно, единственный раз, когда я использую постинкремент / декремент, это циклы while или циклы такого рода. Эти петли одинаковы:
while (x < 5) //evaluates conditional statement
{
//some code
++x; //increments x
}
или
while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
//some code
}
Вы также можете сделать это при индексации массивов и тому подобного:
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);
И т. Д.
Просто для записи, в C ++, если вы можете использовать любой (то есть), вы не заботитесь о порядке операций (вы просто хотите увеличить или уменьшить и использовать его позже), оператор префикса более эффективен, так как он не необходимо создать временную копию объекта. К сожалению, большинство людей используют posfix (var ++) вместо префикса (++ var), просто потому, что это то, что мы узнали изначально. (Меня об этом спросили в интервью). Не уверен, что это правда в C #, но я предполагаю, что это будет.