Yes, there is a difference.
Using Visual Studio 2017 15.9.8 targeting .NET Framework 4.6.1. Consider the sample below.
static void Main(string[] args)
{
// Make sure our null value is not optimized away by the compiler!
var s = args.Length > 100 ? args[100] : null;
var foo = string.Empty;
var bar = string.Empty;
foo = s ?? "foo";
bar = s != null ? s : "baz";
// Do not optimize away our stuff above!
Console.WriteLine($"{foo} {bar}");
}
Using ILDasm it becomes clear that the compiler does not treat those statements equally.
?? operator:
IL_001c: dup
IL_001d: brtrue.s IL_0025
IL_001f: pop
IL_0020: ldstr "foo"
IL_0025: ldloc.0
Conditional null check:
IL_0026: brtrue.s IL_002f
IL_0028: ldstr "baz"
IL_002d: br.s IL_0030
IL_002f: ldloc.0
Apparently, the ?? operator implies a duplication of the stack value (should be the s variable right?). I ran a simple test (multiple times) to get a feeling of which of the two is faster. Operating on string, running on this particular machine, I got these average numbers:
?? operator took: 583 ms
null-check condition took: 1045 ms
Benchmark sample code:
static void Main(string[] args)
{
const int loopCount = 1000000000;
var s = args.Length > 1 ? args[1] : null; // Compiler knows 's' can be null
int sum = 0;
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
for (int i = 0; i < loopCount; i++)
{
sum += (s ?? "o").Length;
}
watch.Stop();
Console.WriteLine($"?? operator took {watch.ElapsedMilliseconds} ms");
sum = 0;
watch.Restart();
for (int i = 0; i < loopCount; i++)
{
sum += (s != null ? s : "o").Length;
}
watch.Stop();
Console.WriteLine($"null-check condition took {watch.ElapsedMilliseconds} ms");
}
So the answer is yes, there is a difference.
UPDATE
Analyzing the IL instructions on sharplab.io we can see that ?? operator produces a dup instruction whereas the ternary operator does not. Benchmarks indicate that the ?? operator produces faster code.
I believe the optimizer/jitter is able to perform some tricks when it knows there are no side effects. I.e. a duplicated value from dup will not change through its lifetime whereas the value from ldarg.1 could change, e.g. from another thread.
PS. StackOverflow should auto-warn posts mentioning "performance" and "negligible" in the same sentence. Only the original poster can know for sure if a time unit is neglible.