If you're already using the nullability feature introduced in C# 8.0, you're aware that C# only reports a warning when there's an attempt to assign a null value to a non-nullable field, property, or parameter. C# doesn't generate the code that would throw an exception at runtime if this happens. However, if code outside your control consumes your API, it's still a good idea to check all values for null.
If you find this task repetitive, frustrating, and unworthy of clean code, we share your sentiment.
Rejoice, solving this problem is a one-liner with Metalama! Simply call the VerifyNotNullableDeclarations method from your ProjectFabric.
Note
By default, only your public API is verified. To add checks to your internal API, set the includeInternalApis parameter to true.
Example: enforcing all non-nullable fields, properties, and parameters
In the following example, we use the VerifyNotNullableDeclarations method to inject null checks for our complete public API. Yes, in just one line.
1using Metalama.Framework.Fabrics;
2using Metalama.Patterns.Contracts;
3
4namespace Doc.NotNullFabric;
5
6internal class Fabric : ProjectFabric
7{
8 public override void AmendProject( IProjectAmender amender )
9 {
10 amender.VerifyNotNullableDeclarations();
11 }
12}
1namespace Doc.NotNullFabric;
2
3public class Instrument
4{
5 public string Name { get; set; }
6
7 public Category? Category { get; set; }
8
9 public Instrument( string name, Category? category )
10 {
11 this.Name = name;
12 this.Category = category;
13 }
14}
15
16public class Category
17{
18 // Internal APIs won't be checked by default.
19 internal Category( string name )
20 {
21 this.Name = name;
22 }
23
24 public string Name { get; }
25}
1using System;
2
3namespace Doc.NotNullFabric;
4
5public class Instrument
6{
7 private string _name = default!;
8
9 public string Name
10 {
11 get
12 {
13 return _name;
14 }
15
16 set
17 {
18 if (value == null!)
19 {
20 throw new ArgumentNullException("value", "The 'Name' property must not be null.");
21 }
22
23 _name = value;
24 }
25 }
26
27 public Category? Category { get; set; }
28
29 public Instrument(string name, Category? category)
30 {
31 if (name == null!)
32 {
33 throw new ArgumentNullException("name", "The 'name' parameter must not be null.");
34 }
35
36 this.Name = name;
37 this.Category = category;
38 }
39}
40
41public class Category
42{
43 // Internal APIs won't be checked by default.
44 internal Category(string name)
45 {
46 this.Name = name;
47 }
48
49 public string Name { get; }
50}