The null-conditional operator conditionally accesses a member: if the receiver is null, the expression returns null instead of attempting the access and throwing an exception. section 5.4.4
Use the operator when a value may be null:
- Write products[0]?.Name instead of a longer null guard around products[0]. section 5.4.4
- Assign the result to a nullable variable, such as string?, because the member access may produce null. section 5.4.4
- Combine ?. with ?? when a fallback is required: products[0]?.Name ?? "No Value". section 5.4.4
Safe access in a Razor Page
A page model whose Product property may be null can render @Model.Product?.Name. Model itself is non-null, while the conditional access prevents a missing Product from causing member access. section 23.2.2
Listing 5.17 Null conditional operator in the HomeController.cs file in the Controllers folder
namespace LanguageFeatures.Controllers {
public class HomeController : Controller {
public ViewResult Index() {
Product?[] products = Product.GetProducts();
string? val = products[0]?.Name;
if (val != null) {
return View(new string[] { val });
}
return View(new string[] { "No Value" });
}
}
}
See the complete controller example using products[0]?.Name and a fallback branch. section 5.4.4
Listing 23.4 The contents of the Index.cshtml file in the Pages folder
@page
@model IndexModel
@using Microsoft.AspNetCore.Mvc.RazorPages
@using WebApp.Models;
<!DOCTYPE html>
<html>
<head>
<link href="/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="bg-primary text-white text-center m-2 p-2">
@Model.Product?.Name
</div>
</body>
</html>
@functions {
public class IndexModel : PageModel {
private DataContext context;
public Product? Product { get; set; }
public IndexModel(DataContext ctx) {
context = ctx;
}
public async Task OnGetAsync(long id = 1) {
Product = await context.Products.FindAsync(id);
}
}
}
See the Razor Page listing using @Model.Product?.Name with a nullable Product property. section 23.2.2
