In my prior post I talked about using functional programming null handling features. While this is a valid approach, it is also one that requires a lot of code changes to achieve. If you don’t want to make that drastic of a level of changes, there are a few other options to consider.
This library contains a few attributes that you can use to annotate your classes, methods, properties, fields, and parameters. While these are intended to be analyzed by the ReSharper Visual Studio add-in or the up-and-coming Rider IDE, they have value in their own right even if you don’t use these tools.
NotNull / CanBeNull
Ordinarily you might have a routine that looks something like this:
Looking at this, you’d have to scan the method to determine whether it’s okay to pass in a null
container either when calling the method or when adding new code to a method.
JetBrains.Annotations has a solution for this via the
Here we added attributes to the two parameters indicating what we expect as far as whether they can or cannot be null. Additionally, we annotated the
Analyze method’s return type with
NotNull to indicate that it does not ever return a null value.
These attributes are not enforced by the compiler or runtime, but they are interpreted via Rider and ReSharper.
Above, ReSharper is warning about potentially passing a potentially null value into a method as a parameter decorated as
ItemNotNull / ItemCanBeNull
CanBeNull, you can annotate collections with
ItemCanBeNull to indicate whether or not null values are possible inside of a collection.
Here we note that the collection itself is not null via
NotNull, but the collection can have null entries as annotated by
Pure methods are methods that do not have side effects outside of the method itself or on the objects passed into the method. As such, pure methods can be called infinitely with the same parameters and get the same output without any modifications being made to other objects or systems.
An extremely simple pure method is below:
Pure attribute here is another piece of syntax to help ReSharper and Rider offer warnings if the return value is not being used (meaning the method invoke is meaningless), but it can also be used as documentation for your team to indicate that the method should never be modified to have any observable side effects.
Public API is another simple one. It essentially marks a method as intended to be consumed by something outside of the project and that the class or method should not be considered unused / dead code.
If you were building a class library, for example, you would often have classes or methods not invoked by your code (though hopefully still called by test code) that are used by external applications.
You annotate those members via the
PublicAPI attribute like this:
This attribute can also be helpful in restraining yourself when refactoring / restructuring an application. If you were tempted to change the signature of a public method that is invoked by something outside of your project, you might not otherwise realize it unless it had a
PublicAPI attribute assigned to it – leading to potential crashes or development headaches later on.
There are a number of other attributes that JetBrains uses for display and advanced code completion, but these do not necessarily add much value without those tools. See the online documentation for a larger list of available attributes.
While not for everyone and not explicitly checked by the compiler, Jetbrains.Annotations are an interesting hybrid of inline null-safety documentation and advanced IDE support if you happen to use JetBrains products. If this is something that might help you out, I recommend giving it a try as a low-risk way to be explicit about null values.
If you’re looking for something with more compile-time enforcement, take a look at my article on functional programming techniques to eliminating nulls in C# code.