Двойные вопросительные знаки ('??') vs, если при присвоении одного и того же var

Ссылаясь на следующий ответ SE > .

При написании

A = A ?? B;

это то же самое, что

if( null != A )
    A = A;
else
    A = B;

Означает ли это, что

if( null == A ) A = B;

было бы предпочтительнее, производительность мудрая?

Или могу ли я предположить, что компилятор оптимизирует код, когда один и тот же объект находится в нотации ???

Ответы

Ответ 1

Не беспокойтесь о производительности, это будет незначительно.

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

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

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

_lazyItem = _lazyItem ?? new LazyItem();

Ответ 2

Моим советом было бы проверить IL (промежуточный язык) и сравнить разные результаты. Затем вы можете точно увидеть, к чему все сводится, и решить, что более оптимизировано. Но, как сказал Адам в своем комментарии, вам, скорее всего, лучше всего сосредоточиться на удобочитаемости/ремонтопригодности над производительностью во что-то столь маленьком.

EDIT: вы можете просмотреть IL с помощью ILDASM.exe, который поставляется с визуальной студией и открыть скомпилированную сборку.

Ответ 3

Я просто пробовал это на С# - очень быстро, поэтому в моем методе может быть ошибка. Я использовал следующий код и определил, что второй метод занял около 1,75 раза дольше, чем первый.
@Lockszmith: после редактирования ниже соотношение составляло 1.115 в пользу первой реализации

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

@Lockszmith: я отредактировал код, чтобы отразить рекомендации из комментариев

var A = new object();
var B = new object();

var iterations = 1000000000;

var sw = new Stopwatch();
for (int i = 0; i < iterations; i++)
{   
    if( i == 1 ) sw.Start();
    if (A == null)
    {
        A = B;
    }
}
sw.Stop();
var first = sw.Elapsed;

sw.Reset();
for (int i = 0; i < iterations; i++)
{
    if( i == 1 ) sw.Start();
    A = A ?? B;
}
sw.Stop();
var second = sw.Elapsed;

first.Dump();
second.Dump();

(first.TotalMilliseconds / second.TotalMilliseconds).Dump("Ratio");

Ответ 4

Хотя производительность для ?? незначительна, побочный эффект иногда может быть незначительным. Рассмотрим следующую программу.

using System;
using System.Diagnostics;
using System.Threading;

namespace TestProject
{
    class Program
    {
        private string str = "xxxxxxxxxxxxxxx";
        public string Str
        {
            get
            {
                return str;
            }
            set
            {
                if (str != value)
                {
                    str = value;
                }
                // Do some work which take 1 second
                Thread.Sleep(1000);
            }
        }

        static void Main(string[] args)
        {
            var p = new Program();

            var iterations = 10;

            var sw = new Stopwatch();
            for (int i = 0; i < iterations; i++)
            {
                if (i == 1) sw.Start();
                if (p.Str == null)
                {
                    p.Str = "yyyy";
                }
            }
            sw.Stop();
            var first = sw.Elapsed;

            sw.Reset();
            for (int i = 0; i < iterations; i++)
            {
                if (i == 1) sw.Start();
                p.Str = p.Str ?? "yyyy";
            }
            sw.Stop();
            var second = sw.Elapsed;

            Console.WriteLine(first);
            Console.WriteLine(second);

            Console.Write("Ratio: ");
            Console.WriteLine(second.TotalMilliseconds / first.TotalMilliseconds);
            Console.ReadLine();
        }

    }
}

Запустите результат на моем ПК.

00:00:00.0000015
00:00:08.9995480
Ratio: 5999698.66666667

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

Я предпочел бы использовать if( null == A ) A = B; вместо A = A ?? B;.