if (x == null) x = new X();
versus
x = x ?? new X();
which of these two is actually more performant? once compiled do they effectively wind up as the same thing (would x = x; be a NO-OP as a result)?
Looking at the intermediate language code there is a difference:
.method private hidebysig instance void Method1() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldfld class X Program::x
L_0006: brtrue.s L_0013
L_0008: ldarg.0
L_0009: newobj instance void X::.ctor()
L_000e: stfld class X Program::x
L_0013: ret
}
.method private hidebysig instance void Method2() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldarg.0
L_0002: ldfld class X Program::x
L_0007: dup
L_0008: brtrue.s L_0010
L_000a: pop
L_000b: newobj instance void X::.ctor()
L_0010: stfld class X Program::x
L_0015: ret
}
Here's the code I compiled to get this:
void Method1()
{
if (x == null) x = new X();
}
void Method2()
{
x = x ?? new X();
}
To be sure which is faster you should time both.
Method Initial condition Iterations per second --------------------------------------------------- NullCheck x is null 33 million Coalesce x is null 33 million NullCheck x is not null 40 million Coalesce x is not null 33 million
Conclusion:
The difference when x is not null looks like it might be due to the null coalescing operator assigning the value of x back to x (stfld in IL), whereas the null check jumps over the stfld instruction when x is not null.
Both are so fast that you'd have to have a very tight loop to notice the difference. You should only make these sorts of performance optimizations if you have profiled your code with your data. Different situations, different versions of .NET, different compilers, etc. may produce different results.
In case someone wants to know how I got these results or reproduce them, here's the code I used:
using System;
class X { }
class Program
{
private X x;
private X xNull = null;
private X xNotNull = new X();
private void Method1Null()
{
x = xNull;
if (x == null) x = xNotNull;
}
private void Method2Null()
{
x = xNull;
x = x ?? xNotNull;
}
private void Method1NotNull()
{
x = xNotNull;
if (x == null) x = xNotNull;
}
private void Method2NotNull()
{
x = xNotNull;
x = x ?? xNotNull;
}
private const int repetitions = 1000000000;
private void Time(Action action)
{
DateTime start = DateTime.UtcNow;
for (int i = 0; i < repetitions; ++i)
{
action();
}
DateTime end = DateTime.UtcNow;
Console.WriteLine(repetitions / (end - start).TotalSeconds);
}
private void Run()
{
Time(() => { Method1Null(); });
Time(() => { Method2Null(); });
Time(() => { Method1NotNull(); });
Time(() => { Method2NotNull(); });
Console.WriteLine("Finished");
Console.ReadLine();
}
private static void Main()
{
new Program().Run();
}
}
Disclaimer: No benchmark is perfect, and this bechmark is far from perfect, mainly to keep things simple. I've run numerous different tests e.g. with the methods in a different order, with and without "warming up" first, over different lengths of time, etc. I get roughly the same results each time. I didn't have anything to prove one way or the other so any bias favoring one method or the other is accidental.
There is no interresting performance difference at all. The most important thing is that if (x == null) x = new X(); is much more readable.
To answer your original question: a smart, optimizing compiler would compile x = x ?? new X() in the same way as if (x == null) x = new X();.
Hence leave micro-optimizations on the compiler and concentrate on code readability and clarity.
Update: To learn more about optimization practices read this article on wikipedia and then, in respect to the nature of your question, Google for “premature optimization is the root of all evil”.
x = x smells with side effects and causes the reader to actually have to think about it much more in contrast to the plain if.As others have mentioned, the performance difference between the two is not that different, however there is an important difference between the two, although it's not so apparent from your example.
if (x == null) x = new X(); creates a potential race condition where x can be newed up by another thread between the check for null and the creation, thus losing an object.
x = x ?? new X(); creates a copy of the variable first, thus no potential race condition.
This is more of a problem in situations where you are referencing the object. For instance:
if (x != null) x.DoSomething(); // this can cause a null reference exception
// if another thread nulls x between the check
// and the call to DoSomething()
(x = x ?? new X()).DoSomething() // this should be fine.
x = x ?? … avoids a race condition is simply wrong. Making a presumption that a certain IL gets generated by an arbitrary C# compiler (i.e. without making a reference to a specific compiler version and platform) or that the IL gets translated into a race-condition-free machine code is just plain risky. Anyway, you are free to down vote my own answer, if that helps :-)
Lazy<T>if you really need lazy initialization. It is a bit slower but avoids several difficulties.