Null-state analysis is a C# compiler feature enabled by ASP.NET Core project templates. It warns when code assigns null where it is not expected or accesses a member through a reference that might be null. The aim is to catch potential null-reference errors before the application runs. section 5.4
The placement of `?` matters:
- `string?` can hold a string or null; `string` is declared non-nullable. section 5.4
- `Product?[]` is a non-null array whose elements may be null. `Product[]?` is an array that may itself be null, but whose elements are non-nullable. `Product?[]?` allows both. section 5.4.3
Warnings can move as types are corrected. Changing `GetProducts` to return `Product?[]` accounts for its null element, but a controller receiving that result must then treat each element as potentially null. After a check such as `if (p != null)`, the compiler recognizes that `p.Name` is safe within the guarded branch. section 5.4.3 section 5.4.4
Handle a possibly null product in an MVC action
With `GetProducts()` returning `Product?[]`, the action can use `Product?[] products = Product.GetProducts();` and pass `new string[] { products[0]?.Name ?? "No Value" }` to `View`. The `?.` operator avoids reading `Name` when the element is null; `??` supplies the fallback string. section 5.4.4
The null-forgiving operator, `!`, overrides the compiler’s assessment: `products[0]!.Name` asserts that the element is not null. Use it only when you are confident the assertion is right; it does not provide the null check used by the guarded alternatives. section 5.4.5 section 5.4.4
Listing 5.14 Using a nullable type in the Product.cs file in the Models folder
namespace LanguageFeatures.Models {
public class Product {
public string Name { get; set; } = string.Empty;
public decimal? Price { get; set; }
public static Product?[] GetProducts() {
Product kayak = new Product {
Name = "Kayak", Price = 275M
};
Product lifejacket = new Product {
//Name = "Lifejacket",
Price = 48.95M
};
return new Product?[] { kayak, lifejacket, null };
}
}
}
The `Product` model shows the return type and array contents together: `GetProducts` declares `Product?[]` because one returned element is null. section 5.4.3
