Двойные вопросительные знаки ('??') 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;
.