C # приращение ToString - PullRequest
       22

C # приращение ToString

5 голосов
/ 21 октября 2011

Я добавляю неожиданное поведение из C # / WPF

    private void ButtonUp_Click(object sender, RoutedEventArgs e)
    {
        int quant;
        if( int.TryParse(Qnt.Text, out quant))
        {
            string s = ((quant++).ToString());
            Qnt.Text = s;
        }
    }

Итак, если я получу квант как 1, квант будет увеличен до 2. Но строка s будет 1. Это вопрос приоритета?

EDIT:

Я переписал это как:

            quant++;
            Qnt.Text = quant.ToString();

и теперь это работает, как я ожидал.

Ответы [ 5 ]

6 голосов
/ 21 октября 2011

Вы используете оператор post -increment.Это оценивает к исходному значению, и затем увеличивает.Чтобы сделать то, что вы хотите в однострочнике, вместо этого вы можете использовать оператор pre .:

quant++;
string s = quant.ToString();

С первой версией вам нужно подумать о порядке, в котором все происходит.Во второй версии никаких мыслей не требуется.Всегда цените ясность кода выше, чем краткость.

Легко поверить, что однострочная версия как-то быстрее, но это не так.Возможно, это было правдой в те времена, в системах C 1970-х годов, но даже тогда я сомневаюсь.

6 голосов
/ 21 октября 2011

Проблема в том, что вы используете постинкремент вместо преинкремента ... но зачем вам хотеть написать этот сложный код? Просто выделите побочный эффект (увеличение) и вызов ToString:

if (int.TryParse(Qnt.Text, out quant))
{
    quant++;
    Qnt.Text = quant.ToString();
}

Или даже отказаться от фактического приращения , учитывая, что вы не собираетесь читать значение снова:

if (int.TryParse(Qnt.Text, out quant))
{
    Qnt.Text = (quant + 1).ToString();
}

Где возможно, избегайте , используя составное присваивание в середине других выражений. Это обычно приводит к боли.

Кроме того, создается впечатление, что весь этот анализ и форматирование скрывают реальную модель, то есть где-то должно быть свойство int, которое может быть отражено в пользовательском интерфейсе. Например:

private void ButtonUp_Click(object sender, RoutedEventArgs e)
{
    // This is an int property
    Quantity++;
    // Now reflect the change in the UI. Ideally, do this through binding
    // instead.
    Qnt.Text = Quantity.ToString();
}
1 голос
/ 21 октября 2011

Теперь я сделаю то, что не должно быть сделано ... Я попытаюсь упростить то, что написал здесь Эрик Липперт В чем разница между i ++ и ++ i? Надеюсь, я 'я не пишу слишком много неправильно: -)

Теперь ... Что делают операторы предварительного увеличения и последующего увеличения?Упрощение и игнорирование всей промежуточной копии (и помнить, что они не являются атомарными операторами в многопоточных средах):

оба они являются выражениями (например, i + 1) которые возвращают результат (например, i + 1), но имеют побочный эффект (в отличие от i + 1).Побочным эффектом является то, что они увеличивают переменную i.Большой вопрос "в каком порядке все происходит?"Ответ довольно прост:

  • предварительное увеличение ++i: увеличивает i и возвращает новое значение i
  • после увеличения i++: увеличивает i и возвращает старое значение i

Сейчас ... Важная часть заключается в том, что increments i всегда происходит первым.Затем возвращается значение (старое или новое).

Давайте создадим пример (пример Липперта довольно сложный. Я приведу другой, более простой пример, который не настолько завершен)но этого достаточно, чтобы проверить, верен ли порядок, о котором я говорил ранее, или нет) (технически я приведу два примера)

Пример 1:

unchecked
{
    int i = Int32.MaxValue;
    Console.WriteLine("Hello! I'm trying to do my work here {0}", i++);
    Console.WriteLine("Work done {1}", i);
}

Пример 2:

checked
{
    int i = Int32.MaxValue;
    Console.WriteLine("Hello! I'm trying to do my work here {0}", i++);
    Console.WriteLine("Work done {1}", i);
}

checked означает, что в случае переполнения будет сгенерировано исключение (OverflowException).unchecked означает, что та же операция не вызовет исключения.Int32.MaxValue + 1 обязательно переполнится.С checked будет исключение, с unchecked i станет -1.

Давайте попробуем запустить первый фрагмент кода.Результат:

Hello! I'm trying to do my work here 2147483647
Work done -1

Хорошо ... i был увеличен, но Console.WriteLine получил старое значение (Int32.MaxValue == 2147483647).Из этого примера мы не можем определить порядок постинкремента и вызова Console.WriteLine.

Давайте попробуем запустить второй фрагмент кода.Результат:

System.OverflowException: Arithmetic operation resulted in an overflow.

Хорошо ... Совершенно очевидно, что сначала было выполнено постинкрементное выполнение, вызвало исключение, а затем явно не было выполнено Console.WriteLine (поскольку программа завершилась).

Итак, мы знаем, что приказ, который я сказал, правильный.

Сейчас.Чему вы должны научиться на этом примере?То же самое я узнал много лет назад.Приращения до и после в C и C # хороши для запутанных конкурсов кода.Они не годятся для многих других вещей (но обратите внимание, что C ++ отличается!).Из этого урока я узнал, что есть ровно два места, где вы можете свободно использовать постинкремент, и есть ровно ноль мест, где вы можете свободно использовать постинкремент.

«Безопасный» постинкремент

for (int i = 0; i < x; i++)

и

i++; // Written alone. Nothing else on the same line but a comment if necessary.

Предварительное увеличение "Safe"

(nothing)
0 голосов
/ 21 октября 2011

string s = ((quant++).ToString());

можно распространять как

используйте quant для вызова метода toString () перед увеличением, а затем

выполнить оператор присваивания, а затем

инкремент `квант '

попробуйте с ++ квант.

0 голосов
/ 21 октября 2011

В этом случае сначала будет вызван quant.ToString(), а затем будет увеличен квант.

Если вы напишите ((++quant).ToString()), первый шаг будет увеличивать количество, а затем будет вызван quant.ToString().

...