When working with .NET Standard 2.1 code, I found a strange behaviour when there should have been a warning to a nullable parameter but it does not:
And I can reproduce it with a simple method:
#nullable enable // making sure that nullability is enabled
static void Foo(IEnumerable<string>? a = default)
{
Console.WriteLine(a.Count());
string? b = null;
Console.WriteLine(b.Length);
}
With the above code compiled in netstandard2.1
, there is no warning for a
. Nullable context does work because there is CS8602
(dereference of a possibly null reference) for b
.
When switching to net8.0
for example, the compiler correctly raises CS8604
for a
. This is built using .NET 9 SDK.
What's going on here? Is it a bug in the compiler?
When working with .NET Standard 2.1 code, I found a strange behaviour when there should have been a warning to a nullable parameter but it does not:
And I can reproduce it with a simple method:
#nullable enable // making sure that nullability is enabled
static void Foo(IEnumerable<string>? a = default)
{
Console.WriteLine(a.Count());
string? b = null;
Console.WriteLine(b.Length);
}
With the above code compiled in netstandard2.1
, there is no warning for a
. Nullable context does work because there is CS8602
(dereference of a possibly null reference) for b
.
When switching to net8.0
for example, the compiler correctly raises CS8604
for a
. This is built using .NET 9 SDK.
What's going on here? Is it a bug in the compiler?
Share Improve this question edited Feb 16 at 15:58 Luke Vo asked Feb 16 at 15:38 Luke VoLuke Vo 20.7k25 gold badges125 silver badges230 bronze badges 4 |1 Answer
Reset to default 2.NET standard does not have nullability annotations. It does not use the nullable reference types feature. It's as if you are using a library that has #nullable disable
.
For example, compare how the EqualityComparer<T>.Equals
method is declared. In .NET 9, it's
public abstract bool Equals (T? x, T? y);
In .NET Standard, it's
public abstract bool Equals (T x, T y);
The same goes for the the parameter of the Enumerable.Count
method - it's just that "not nullable" (in a #nullable enable
environment) is syntactically the same as "not annotated" (in a #nullable disable
environment), so there is no visual difference.
Therefore, the compiler is oblivious to what can and can't be null in all the .NET Standard APIs, and the compiler is designed to not raise warnings in such a situation. Otherwise (if the compiler assumes everything is nullable) you will likely get a lot of warnings when you try to use an old, unannotated library.
See also this GitHub issue, which says that it is not planned for .NET Standard to get nullable annotations in the future.
string.IsInterned(null)
? If not, that's probably the problem. Bear in mind that the LINQ methods are extension methods, so they could be declared to accept a null first argument... unless the compiler see that the assembly is annotated with NRT annotations, it can't/shouldn't warn. – Jon Skeet Commented Feb 16 at 15:53a
beingstring?
, usinga.Length
would cause the warning, whilea.Count()
would not. So yes it's due to extension method. And in my screenshot,Append
indeed is an extension method as well. – Luke Vo Commented Feb 16 at 15:59null
there is not getting any warning. Great find there. – Luke Vo Commented Feb 16 at 16:03