1

I have this bit of relevant code:

if (boardMap[i,j] != null) {
    Console.Write(boardMap[i,j].color.ToString() + " " + boardMap[i,j].type.ToString());    
}
else {
    Console.Write("X");
}

boardMap contains potentially null values, which is why I implemented the if statement checking if the boardMap[i,j] item is null. However, I get a warning in line 2 telling me that boardMap[i,j] is possibly null.
How do I fix this -> What is the correct way to do null checks like this?

(Please note, I am very much a beginner with dotnet and C#)

  • 2
    What VS versoin? While I would move the value out into a variable first (avoid multiple boardMap[i,j] accesses - this smells like a warning error. Given that you DO test for null, unless color can be null (which you do not test) this seriously looks like a parsing error. Which may be fixed with a newer version of Roslyn. – TomTom Nov 19 '21 at 20:20
  • Keep in mind that `boardMap[i,j].color` and `boardMap[i,j].type` can be null as well. – Progman Nov 19 '21 at 20:25
  • Support for arrays is not that impressive to begin with. `A[] a = new A[5]; Console.WriteLine(a[3].ToString());` crashes at runtime but doesn't warn, even though the array is initialized to all `null` values. Obviously verifying initialization of the whole array is a little beyond the reach of static analysis, but still. – Jeroen Mostert Nov 19 '21 at 20:27
  • 1
    @TomTom It [reproduces](https://dotnetfiddle.net/5EGdiI) for me (i use the release version of .NET 6 and latest VS). – Guru Stron Nov 19 '21 at 20:28
  • @TomTom newest VS Code with an up-to-date C# extension, .net framework 6 – Adam Wójcik Nov 19 '21 at 20:34
  • @Progman In my case, the `.color` and `.type` fields can't be null, should've included that in the question – Adam Wójcik Nov 19 '21 at 20:35
  • This would warrant a bug report. Unless color or type are nullable, this is a false error imho. – TomTom Nov 19 '21 at 20:39

4 Answers4

1

Currently compiler does not handle this case very well (and arrays in general). To help compiler determine the null-state of the item you can use pattern matching with empty property pattern:

if (boardMap[i,j] is {} map) 
{
    Console.Write(map.color.ToString() + " " + map.type.ToString());    
}
else
{
    Console.Write("X");
}

or introduce a variable:

var map = boardMap[i,j];
if (map != null) 
{
   ...
}
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • If the value is null on first call then it's also null on any other call (unless changed). Packing it in a variable will not change that. The empty property pattern would be enough. – DanielD Nov 19 '21 at 20:37
  • @DanielD It does not change the "truth" but it changes the output of compiler cause currently nullability static flow analysis does not handle the OP case well, while it can handle separate variable. So I agree that empty property pattern **should** be enough, but it is not for the compiler ATM. – Guru Stron Nov 19 '21 at 20:43
  • Well, point for you as OP didn't specify whether he just doesn't want the warning for a possible null value to be displayed anymore, or whether he actually wants to handle a possible null value. Still your first option handles the null value, the latter just removes the warning. – DanielD Nov 19 '21 at 20:44
  • @DanielD _", the latter just removes the warning."_ no, it handles it as good as the first one. Inside the `if` block `map` will be considered as not null by compiler and outside - compiler will give nullability warnings. – Guru Stron Nov 19 '21 at 20:50
  • again you're right, it's late :) ofc both solutions check against null values, just ment it doesn't change anything compared to OP's direct access, except better variable usage (no need to get value from array each time). – DanielD Nov 19 '21 at 20:53
1

As of C# 8.0 and later, you can use the null-forgiving operator. Just append ! after whatever might be null. It basically tells the compiler that it should turn off possibly null warnings for this occurrence.

if (boardMap[i,j] != null) {
    Console.Write(boardMap[i,j]!.color.ToString() + " " + boardMap[i,j]!.type.ToString());    
}
else {
    Console.Write("X");
}
Alex Charters
  • 301
  • 2
  • 12
  • 1
    Not a solution, imho, but a workaround. Because this basically eliminates the nul as possible value - TOTALLY. – TomTom Nov 19 '21 at 20:46
  • keep in mind that this doesn't solve your null value exceptions at runtime, but simply removes the null warning of the compiler. – DanielD Nov 19 '21 at 20:46
  • @DanielD JFYI the nullable reference types feature does not guarantee that you will not have the null reference exceptions at runtime. – Guru Stron Nov 19 '21 at 20:49
1

In a multithreaded app boardMap[i,j] could potentially be set to null 10 nanoseconds after you've checked it not to be null. That's (probably) why the compiler now complains. Of course it depends on your code. If you're sure that array is only handled by one thread, your null check is safe as is and you can just ignore the warning here.

An easy way to protect you code in a multithreaded scenario (without locking) is to assign the array value to a local variable. And do the null check and the Console.Write on that variable. Then the null check is safe. See post by @GuruStron

lidqy
  • 1,891
  • 1
  • 9
  • 11
0

Despite your if, the compiler is not able to infer that boardMap[i,j] won't be null, so it issues this warning.

EDIT @GuruStron points out that this kind of warning is only issued since C#8. I was not able to find the reference for this, but I'm inclined to believe it. Which implies that if one has this problem, he is using at least C#8.

You can deal generally with this kind of issues in different ways, depending on your needs.

Laurent Gabiot
  • 1,251
  • 9
  • 15
  • Thanks for the feedback, I'll give the docs you linked a read. I ended up solving the problem by the forgiveness operator `!` for now – Adam Wójcik Nov 19 '21 at 20:43
  • "Use C#8 (if you can)" - OP should already be using it otherwise the should not be the warning. – Guru Stron Nov 19 '21 at 20:44
  • Actually at this point "Use C# 10.0" would possibly be better. I think if you use 10.0 there are different roslyn analyzers and I think I read somewhere that null check was an area they improved. – TomTom Nov 19 '21 at 20:47
  • Thanks @GuruStron, I'll correct. – Laurent Gabiot Nov 19 '21 at 20:47