Using the following project file settings:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net5.0</TargetFrameworks>
<LangVersion>9.0</LangVersion>
<Nullable>enable</Nullable>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<AnalysisLevel>latest</AnalysisLevel>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
</PropertyGroup>
</Project>
with the following code:
using System;
namespace TestArrayValueHashCodeNullability
{
public static class Test
{
/// <summary>
/// Gets a hash code for the array based on the values in the array.
/// </summary>
/// <typeparam name="TYPE">The type of item in the array.</typeparam>
/// <param name="array">The array to get the value hash code for.</param>
/// <returns>A hash code based on the values in the array.</returns>
public static int ValueHashCode<TYPE>(this TYPE[] array)
{
if (array == null) throw new ArgumentNullException(nameof(array));
int code = array.Length;
// loop through each element and compare
for (int offset = 0; offset < array.Length; ++offset)
{
int elemhashcode;
elemhashcode = array[offset]?.GetHashCode() ?? 0; // either this line should work
elemhashcode = array[offset].GetHashCode(); // or this one should
code ^= (elemhashcode >> (32 - (offset % 32)) ^ (elemhashcode << (offset % 32)) ^ 0x1A7FCA3B);
}
return code;
}
}
}
I get the the following warnings on the two alternative elemhashcode = lines, which appear to be in direct conflict with each other. I believe that one of the lines should compile without a warning, as array[offset] is possibly null on that line or it is not--it cannot be both "possibly null" and "never null".
Test.cs(21,32,21,45): warning CA1508: 'array[offset]' is never 'null'. Remove or refactor the condition(s) to avoid dead code.
Test.cs(21,32,21,60): warning CA1508: 'array[offset]?.GetHashCode()' is never 'null'. Remove or refactor the condition(s) to avoid dead code.
Test.cs(22,32,22,45): warning CS8602: Dereference of a possibly null reference.
I can get the warning to go away using the following code:
elemhashcode = array[offset]!.GetHashCode();
but that shouldn't be necessary. One or the other should be technically correct. Is this a compiler bug, or am I missing some subtle solution to this?