Why is it still possible to assign null to non nullable reference type?

Viewed 3071

I am confused. I thought enabling c# 8 and nullable reference types will prevent the assignment of null to a non nullable reference types, but apparently it is only a warning at compile time, I know you can enforce it to be an error and stop it build, but I thought it is more than just a compiler check.

Look at this example https://dotnetfiddle.net/4eCs5L

If you run, it is still possible to assign null to non nullable reference type, why isn't that throwing an error at run time?

3 Answers

TLDR: Backwards compatibility

If Nullable Reference Types would have been part of C# 1, then a null assignment to a non-nullable type would emit a compile error.

The problem of C# is there is already a lot of existing code without Nullable Reference Types. Compiler errors on null assignment would break all that existing code or libraries.

You can find the full explanation in the .NET Blog Post from the C# Program Manager: https://devblogs.microsoft.com/dotnet/nullable-reference-types-in-csharp/

The purpose of the feature is to give developers more tools to catch the most prevalent type of errors there is, derefencing a null reference / pointer and thus crashing the application.

As such, the C# design team added "nullable reference types", with enough syntax that the developer can more clearly declare the intent and requirements of code.

Things that can be expressed by the new syntax:

  • Properties and fields that either allow NULL or does not allow NULL
  • Method parameters that can be NULL, or should be NULL
  • Method return values that can be NULL, or won't be NULL

When enabled, the compiler will use this new syntax, and attributes and other metadata, to start giving warnings when it sees code that isn't "guaranteed" to be correct. In other words, if you read a property that says it can return NULL, and try to just pass that in as a parameter value where the method says that the parameter shouldn't be NULL, you will get a warning.

You can, using existing directives on projects, say that certain warnings should instead be handled as errors, and break the build, and this includes these new warnings.

HOWEVER, what they didn't add was runtime checks. If you say that a parameter value should never be NULL, and either ignore the warning or bypass it (there are ways to say "trust me, this is correct"), then the method will run as stated. There are no invisible if-statements or guard statements that verify that the parameter is not null.

Basically, you should still add such if-statements.

This is, contrary to your belief, exactly what they designed the feature to do. They did not forget to add these runtime checks, they purposefully didn't add them.

For instance, if you call a method through reflection, the compiler is not involved since it is a runtime thing, and thus no checks will be performed at all. If the method doesn't have such guard statements, likely it will crash later with a NullReferenceException.

Using this reference https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references

I can see that the directive #nullable enable: Sets the nullable annotation context and nullable warning context to enabled

If you are still expecting it to throw error, add this to your project file <WarningsAsErrors>nullable</WarningsAsErrors>

Compiler warnings for null assignments

Related