-
-
Notifications
You must be signed in to change notification settings - Fork 3
Nullability
Cesil can be configured to perform some checks at runtime to prevent null values from occuring where they are not expected. While this functionality is primarily for supporting C# 8's new nullable reference types, checks can be configured in null oblivious contexts and for nullable value types.
Runtime null checks are intended to prevent the subversion of user nullability annotations. Accordingly, if the .NET runtime would prevent null from appearing then Cesil may decline to emit any additional null checks. For example, if a Setter
is backed by an instance method and forbids null rows then Cesil may not explicitly check that a row is non-null as the runtime will raise a NullReferenceException
before the Setter
's method executes.
Getters, InstanceProviders, Resets, Setters, and ShouldSerializes have a notion of "row nullability" - whether the produced or taken row is allowed to be null
. Each exposes an AllowNullRows()
and ForbidNullRows()
method.
AllowNullRows()
returns an equivalent wrapper which will cause no runtime checks for null rows to be performed. Be aware that AllowNullRows()
allows you to subvert nullable reference type annotations. It is an error to allow null rows if the row is a non-nullable value type.
ForbidNullRows()
returns an equivalent wrapper which will cause a runtime check for null rows to be performed, if it is possible for a null to be present at runtime. It is legal to forbid null rows even if the row is a nullable value type.
It is illegal to call either AllowNullRows()
or ForbidNullRows()
on a wrapper that does not take or produce a row.
Formatters, Getters, Parsers, and Setters have a notion of "value nullability" - whether the produced or take value is allowed to be null
. Each exposes an AllowNullValues()
and ForbidNullValues()
method.
AllowNullValues()
returns an equivalent wrapper which will cause no runtime checks for null values to be performed. Be aware that AllowNullValues()
allows you to subvert nullable reference type annotations. It is an error to allow null values if the value is a non-nullable value type.
ForbidNullValues()
returns an equivalent wrapper which will cause a runtime check for null values to be performed, if it is possible for a null to be present at runtime. It is legal to forbid null values even if the value is a nullable value type.
For wrappers that allow chaining with Else()
, the most restrictive null check will be used by the newly created wrapper.
Concretely, that means that:
-
Formatters
- if either forbids null values, then the new
Formatter
will forbid them
- if either forbids null values, then the new
-
InstanceProviders and Parsers
- if the first wrapper in the chain cannot produce nulls (it is backed by a constructor) then the new wrapper will not inject null checks
- if any part of the chain can produce nulls, then the new wrapper can produce nulls
Once chained, wrappers are treated as a single unit - so using any of the AllowNullXXX()
methods may result in subverting null annotations.