Автоматические свойства C # - Все еще нулевые после + =? - PullRequest
9 голосов
/ 26 августа 2009

Мне это кажется ошибкой ...

Я принимаю, что автоматические свойства определены так:

public decimal? Total { get; set; }

Будет нулевым при первом доступе к ним. Они не были инициализированы, поэтому, конечно, они нулевые.

Но даже после установки их значения через + = это десятичное число? все еще остается нулевым. Итак, после:

Total += 8;

Итого по-прежнему равно нулю. Как это может быть правильно? Я понимаю, что он делает (ноль + 8), но кажется странным, что он не понимает, что это означает, что он должен быть установлен на 8 ...

Дополнения:

В своем вопросе я поставил точку «ноль + 8» - но обратите внимание, что она работает со строками. Таким образом, он делает null + "привет" просто отлично и возвращает "привет". Поэтому, за кулисами, он инициализирует строку в строковый объект со значением «привет». Поведение должно быть таким же для других типов, IMO. Это может быть потому, что строка может принимать значение NULL в качестве значения, но, тем не менее, строка NULL не является инициализированным объектом, верно?

Возможно, это просто потому, что строка не может быть обнуляемой ...

Ответы [ 10 ]

31 голосов
/ 26 августа 2009
public decimal? Total { get; set; }

Думайте о null как о "неизвестном значении". Если у вас есть неизвестное количество чего-то и вы добавляете еще 8, сколько у вас сейчас?

Ответ: неизвестен.

Операции над переменными Nullable

В есть случаи, когда операции с неизвестными значениями дают доступных для понимания результатов.

public bool? State { get; set; }

Следующие операторы имеют известные решения, даже если они содержат неизвестные значения:

State = null;
nextState = State & false;         // always equals false
nextState = State & true;          // still unknown (null)

nextState = State | true;          // always true
nextState = State | false;         // still unknown (null)

Видите образец?

Конечно, если вы хотите, чтобы Total было равно (равно) 0, когда оно равно null, вы можете использовать нуль-оператор объединения и написать что-то вроде это:

Total = (Total ?? 0) + 8;

Это будет использовать значение Total в вашем уравнении , если это null, и в этом случае оно будет использовать значение 0.

7 голосов
/ 26 августа 2009
Null + 8 = Null

Вам нужно будет установить его на ноль раньше.

5 голосов
/ 26 августа 2009

null означает неизвестное значение,

unknown value + known value = still unknown value
3 голосов
/ 26 августа 2009

Вот одна строка для инициализации при первом вызове и последующего увеличения:

    public void InitializeOrIncrement(decimal value)
    {
        // if Total is null then initialize, otherwise increment
        Total = (Total == null) ? value : Total + value;
    }

    public decimal? Total { get; set; }
2 голосов
/ 26 августа 2009

С MSDN :

При выполнении сравнения с обнуляемые типы, если значение одного из обнуляемые типы нулевые, а другого нет, все сравнения оценивают в ложь, кроме! = (не равно). Это важно не предполагать, что потому что конкретное сравнение возвращает false, обратный случай возвращает истину.

Итак, все работает как задумано.

1 голос
/ 13 апреля 2010

Как уже отмечали другие люди, ноль не равен нулю. Хотя может показаться более удобным, что нулевое целое число по умолчанию равно нулю в долгосрочной перспективе, оно может привести к странным результатам, которые вы можете не увидеть, пока не станет слишком поздно.

В качестве быстрого примера, скажем, один из ваших каналов данных не работает и заполняет ваш набор результатов значениями NULL. Ваши вычисления будут рассматривать нули как нули, и продолжит давать результаты . Поскольку числа все еще выходят, хотя они, вероятно, ошибочны, вы можете никогда не заметить, что что-то пошло не так.

1 голос
/ 26 августа 2009

Я знаю, что имеет смысл сделать

public decimal? Total { get; set; }

Total = (Total ?? 0) + 8;

но не проще ли это сделать:

public decimal Total { get; set; }

начальное значение Total составляет 0

0 голосов
/ 26 августа 2009

публичный десятичный? Всего {получить; задавать; }

Хотелось бы что-нибудь подобное? Какой-то тип автоматической инициализации, если значение еще не установлено.

public decimal? Total
{
  get { return this.totalValue;}
  set
  { 
     if(totalValue == null) { this.totalValue = 0;}
     this.totalValue = value;
  }
}

private decimal? totalValue;
0 голосов
/ 26 августа 2009

Ноль не равен нулю. Ноль плюс восемь - это восемь ... но ноль плюс восемь? Всегда ноль. Точно так же, как бесконечность плюс что-то еще бесконечность - она ​​не определена.

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

0 голосов
/ 26 августа 2009

для установки значения Всего просто

Total = 8;

Я бы порекомендовал прочитать Nullable Types , чтобы понять, как они работают. Вы можете проверить, имеет ли свойство значение, используя HasValue.

С MSDN :

Операторы

Предопределенные унарные и двоичные операторы и любые пользовательские операторы, которые существуют для типов значений также могут быть использованы обнуляемыми типами. Эти операторы выдают нулевое значение если операнды нулевые; иначе, оператор использует содержащееся значение рассчитать результат. Например:

int? a = 10;
int? b = null;

a++;         // Increment by 1, now a is 11.
a = a * 10;  // Multiply by 10, now a is 110.
a = a + b;   // Add b, now a is null.
...