Понимание нулевого коалесцирующего оператора (??)


У меня есть пользовательский WebControl, который реализует .Value геттер / сеттер, возвращающий Nullable

Это отфильтрованное текстовое поле на стороне клиента (подкласс TextBox с включенным javascript и некоторой логикой на стороне сервера для установки / получения значения)

Вот геттер и сеттер из этого элемента управления:

public decimal? Value
{
    get
    {
        decimal amount = 0;
        if (!decimal.TryParse(this.Text, NumberStyles.Currency, null, out amount))
        {
            return null;
        }
        else
        {
            return amount;
        }
    }
    set
    {
        if (!value.HasValue)
        {
            this.Text = "";
        }
        else
        {
            this.Text = string.Format("${0:#,##0.00}", value);
        }
    }
}

Проблема, которую я вижу, заключается в том, что вывод из этого утверждения:

decimal Amount = uxAmount.Value ?? 0M;

Я вижу, что сумма устанавливается в "0", Когда uxAmount.Value возвращается 10000.

Это сработало, как я и ожидал (извините за изменение в корпусе):

decimal? _Amount = uxAmount.Value;
decimal amount = _Amount ?? 0;

Я также видел это поведение (недавно) при вызове функции UDF, определенной в контексте данных Linq2Sql, вместе с оператором null coalescing, то есть я знал, что мой вызов UDF вернул ожидаемое значение, но вместо этого я получал значение RHS.

Еще больше запутывает меня, если я оцениваю uxAmount.Значение в часах, я получаю 10000 типа Nullable<decimal>.

Вот некоторые выражения, которые я имел попробовал:

decimal? _Amount = uxAmount.Value; //10000
decimal amount = _Amount ?? 0; //10000
decimal amount2 = _Amount ?? 0M; //10000
decimal Amount = uxAmount.Value ?? 0M; //0

Затем я добавил Это выражение после приведенных выше 4

decimal amount3 = (uxTaxAmount.Value) ?? 0M;

Теперь

decimal Amount = uxAmount.Value ?? 0M; //10000
decimal amount3 = (uxAmount.Value) ?? 0M; //0

Похоже, что последний вызов всегда равен 0, но значение uxAmount.Value (которое разбирается из .Text согласно приведенному выше геттеру/сеттеру с использованием TryParse стабильно. Я остановлен в точке останова, и нет никаких других потоков, которые могли бы манипулировать этим значением.

Обратите внимание на использование суффикса M, чтобы принудить константу к десятичной, поскольку она была целочисленной, и я подозревал, что преобразование типа вопрос.

Есть идеи?

Значение как LHS, так и RHS, по-видимому, является стабильным и известным.

-- edit-- некоторые скриншоты из VS2010

Шагая через код, показывающий значение amount3

Смотрите диалог и еще немного подробностей о состоянии переменных

2 8

2 ответа:

(этот ответ был построен из моих комментариев выше.)

Вы уверены, что отладчик dsiplays это правильно для вас? Вы пробовали перейти на несколько строк ниже, чтобы убедиться, что у вас есть обновленное значение amount3?

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

Я видел, как другие опытные разработчики были сбиты с толку подобными ситуациями, поэтому я знаю, что отладчик иногда "на одну строку кода" отстает, когда смотрит на назначение локальной переменной. Может быть, кто-нибудь найдет ссылку, обсуждающую это?

Взгляните на этот аналогичный вопрос

Используя срастанию нулевой оператор на типы, допускающие значение null изменения неявного типа

Почему бы просто не сделать

decimal amount = uxTaxAmount.Value.HasValue ? uxTaxAmount.Value.Value : 0M

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