как ведет себя тривиальная арифметика с нулевым слиянием - PullRequest
4 голосов
/ 28 апреля 2020

У меня есть метод

int? Foo(int? a, int? b)
{
    return a ?? 0 + b ?? 0;
}

Я был удивлен, что результат Foo(12, 4) равен 12, хотя я ожидал 16.

Я знаю, что нуль-слияние очищает тип от nullabilty , Итак, я подумал, что, возможно, обнуляемые типы не связаны со структурами. Но выражение (int?) 12 + (int) 4 возвращает ожидаемое 16.

Похоже, что только выражение с объединением ведет себя неочевидно: (int?) 12 ?? 0 + (int) 4 дает 12.

Почему каждый из приведенных выше примеров не возвращает 16?

Ответы [ 4 ]

3 голосов
/ 28 апреля 2020

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

int? Foo(int? a, int? b)
{
    return (a ?? 0) + (b ?? 0);
}

Ваша версия вычисляет следующее:

int? Foo(int? a, int? b)
{
    return a ?? ((0 + b ) ?? 0);
}
1 голос
/ 28 апреля 2020

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

private int? Foo(int? a, int? b)
{
    int? num = a;
    int valueOrDefault;
    if (!num.HasValue)
    {
        int? num2 = b;
        int? num3 = num2.HasValue ? new int?(num2.GetValueOrDefault()) : null;
        valueOrDefault = num3.GetValueOrDefault();
    }
    else
    {
        valueOrDefault = num.GetValueOrDefault();
    }
    return valueOrDefault;
}

Добавление скобок к return (a ?? 0) + (b ?? 0); из-за более низкого приоритета оператора ?? решит ситуацию. Под капотом будет

private int? Foo(int? a, int? b)
{
    return a.GetValueOrDefault() + b.GetValueOrDefault();
}
1 голос
/ 28 апреля 2020

Причина ответа 12

return a ?? 0 + b ?? 0;

интерпретируется как

return a ?? ((0 + b) ?? 0);

как результат

return 12 ?? ((0 + 4) ?? 0)  => 12

Ссылка: приоритет оператора

важное примечание

Операторы, ассоциированные справа, оцениваются в порядке справа налево. Операторы присваивания, операторы слияния нуля и условный оператор?: Ассоциативны справа.

1 голос
/ 28 апреля 2020

Ваш метод ведет себя так:

int? Foo(int? a, int? b)
{
    if (a == null)
    {
        int? temp = 0 + b;              
        if (temp == null)
        {
            return 0;
        }
        else
        {
            return temp;
        }
    }
    else
    {
        return a;
    }
}

Чтобы заставить его вести себя так, как вы ожидаете, вы должны установить скобки

int? Foo(int? a, int? b)
{
    return (a ?? 0) + (b ?? 0);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...