Non-nullable types set to null by libraries

92 views Asked by At

I recently tried to enable nullable context for my C# projects. It is great mainly for the reason that if I use non-nullable types I can rely on a reference to have a proper object stored in it.

Or at least that's what I thought. Unfortunately, I sometimes see null references in my non-nullable types when I use external libraries. E.g

  • If I use System.xml.serialization.xmlserialier.Deserialize() and the resulting object has a non-nullable field. Deserialize would put null into fields of the returned object - even if they are non-nullable.

  • I also use a 3rd party library called AutoMapper . The library has a similar behaviour - it just produces objects which violates the non-nullable assumption and I don't see an option to change this.

How do you deal with this situation? I am not sure if

  • I just have chosen my libraries badly and there are better libraries that do not write null to non-nullable fields.

  • I have to check all objects manually if they are coming from external code?

  • I completely missed the point of these non-nullable types...? I thought the idea is that I can rely on not having null for these types if my code does not spit out compiler warnings.

I tried to find specific solutions for the mentioned libraries. However both seem unaware and don't provide a flag "Throw exception if null" or similar.

2

There are 2 answers

0
Heinzi On

... if I use non-nullable types I can rely on a reference to have a proper object stored in it.

True, but it's not a hard run-time guarantee. It's a "static code analysis" check at compile time, which is easy to "override":

  1. You can use the null-forgiving operator ! to assign null to a variable or field of a non-nullable reference type.

  2. You can use reflection to assign null.

  3. VB code calling your C# library will happily ignore all the nullable annotations in your library.

In your compiled code, the field is technically still "nullable". Sure, the compiler will set helpful attributes and .NET 6+ even has an API to check for these attributes, but it's still "just" an annotation, not a run-time type check that will cause the CLR to bail out with an exception.

That's why, as a library developer, you still need to do runtime checks against null argument values:

public void MyMethod(string s)
{
    // I have declared s as non-null, but users of my library
    // are free to ignore that annotation.
    ArgumentNullException.ThrowIfNull(s);

    ...
}

How do you deal with this situation?

Be careful with deserialization, object-relational mappers and other libraries which use reflection to dynamically fill your objects. Many of them have been written before nullable reference types were a thing. Check the documentation whether they respect nullability attributes or not. If they don't, validate your objects before using them.

0
Ian Kemp On

I completely missed the point of these non-nullable types...?

Yes, you did.

The point of nullable reference types (NRTs) is to allow you to tell the compiler "hey, this reference type shouldn't be null at this point", thus enabling the compiler to alert you when that constraint is violated. This allows you to write code that as far as possible avoids the dreaded unexpected NullReferenceException (NRE).

That's all that NRTs are: a compile-time way to write safer code. They are not, and cannot be, a magic bullet that prevents nulls from happening, because that is a runtime consideration.