It's due to the compiler difference.
In this fiddle, https://dotnetfiddle.net/5GgGNS, you can see the error, which is omitted in the mono compiler.
I think the error is valid due to the fact that this line
if (myDict?.TryGetValue("hello", out var value) == true)
is not guaranteed to initialize the local variable value
.
If you would rewrite it to:
if (myDict?.TryGetValue("hello", out var value) == null)
it would try to access value
.
Now, the null
value, or true
in your case, could be a function's return value, which would only be known at run time.
But, since all variables are basically always initialized, it's just a compiler feature.
On the other hand, according to the C#5 specs:
A local variable introduced by a local-variable-declaration is not automatically initialized and thus has no default value. For the purpose of definite assignment checking, a local variable introduced by a local-variable-declaration is considered initially unassigned. A local-variable-declaration may include a local-variable-initializer, in which case the variable is considered definitely assigned only after the initializing expression (§5.3.3.4).
But your code is C# 6.
So my conclusion is that the compilers interpret it differently. The Microsoft compiler takes the ?.
operator into account. You should file it as a bug, or finding at least, maybe even at both parties.
Argumentation
Fun fact, if you use this code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
//Your code goes here
Dictionary<string,int> myDict = null;
if (myDict?.TryGetValue("hello", out var value) == null)
{
Console.WriteLine("Hello" + value.ToString());
}
}
}
[using https://www.jdoodle.com/compile-c-sharp-online , mono 5.10.1]
You'll see the actual initialization to default(T)
at work. The output is Hello0
. Nevertheless, it's remarkable because due to the ?
, and the fact that myDict
is null
, TryGetValue
shouldn't be called and leaving value
"uninitialized".
The null-conditional operators are short-circuiting. That is, if one operation in a chain of conditional member or element access operations returns null, the rest of the chain doesn't execute.
source
But..., since there are no uninitialized variables; if it compiles, the compiler will make sure it's behavior is not undefined.
So, since value
is initialized, on run-time, the question remains if it's a valid compiler error at build time. Regarding to the run-time intend of the code it is (and that's why the error was there in the first place), but I think it remains a grey area.
Do note that according to this default(T)
is not override-able, which would actually lead to no condition where it fails.
By running this little test:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
//Your code goes here
Dictionary<string,int> myDict = null;
if (myDict?.Bar(out var test) == null)
{
Console.WriteLine("does hit");
}
}
}
static class Foo
{
public static object Bar(this Dictionary<string,int> input, out int test)
{
test = 3;
Console.WriteLine("does not hit");
return 1;
}
}
[using https://www.jdoodle.com/compile-c-sharp-online , mono 5.10.1]
The output becomes:
does hit
And you can verify the correct run-time behavior of the ?.
operator.