I can't seem to wrap my head around the compiler's warning in this case:
using System;
using System.Collections.Generic;
#nullable enable
public class Program
{
public static void Main()
{
Guid guid = Guid.NewGuid();
Dictionary<Guid, string> d = new();
bool found = d.TryGetValue(guid, out string? str);
if (found is false)
{
return;
}
string s = str; // WARNING: possible null value
}
}
After all, I'm doing the found
check and return if there is no value (e.g. when the out str
value is null). Plus, the out
parameter of the .TryGetValue
method is annotated with [MaybeNullWhen(false)]
.
Would appreciate your help figuring our where I'm wrong in my expectations and fixing the code, thanks. Code is here.
Basically the compiler (or language specification) isn't "smart" enough to carry the conditional processing of the return value from TryGetValue
over when you use a local variable.
If you inline the TryGetValue
call into the if
condition, it's fine:
if (!d.TryGetValue(guid, out string? str))
{
return;
}
string s = str; // No warning
It's possible that over time this will evolve to be more sophisticated, but it's relatively difficult to specify this sort of thing in a bullet-proof way.
This isn't limited to nullable reference types - there are other cases where logically code is fine from a human perspective, but the compiler will reject it. For example:
string text;
bool condition = DateTime.UtcNow.Hour == 5;
if (condition)
{
text = "hello";
}
if (condition)
{
Console.WriteLine(text); // Error: use of unassigned local variable
}
We know that if we get into the second if
statement body, we'll also have gone into the first one so text
will have been assigned a value, but the rules of the compiler don't attempt to be smart enough to spot that.