string name and string? name are the same type at runtime. The difference is a contract the compiler enforces in this project. Ignore it and you are back to null checks you hoped the type system had finished.
This is not the OOP question bank. Class versus interface lives on C# OOP interview questions. Hub: Architecture.
Real-world analogy
A form field marked "required" does not weld the pen to the page. It tells the clerk to send the form back if the field is empty. Nullable annotations are that mark. Someone can still smuggle a blank form through if the clerk stamps it with "I checked" without looking. That stamp is the ! operator.
Worked example
A DTO has string Email { get; set; } = "" only to silence a warning. JSON posts { "email": null } because the Angular side sent a cleared input. The deserializer sets Email to null. The compiler was happy. The next line calls email.Trim() and throws. The honest property is string? Email if missing is allowed, and the action returns 400 before Trim. If missing is not allowed, a required validation attribute rejects the body. The empty-string initializer was a lie that moved the crash one line later.
| You mean | Write | Do not write |
|---|---|---|
| Caller must pass a string | string | string name = null! |
| Missing is normal | string? | a magic "" that means missing |
| You just proved it is not null | a local check, then use it | ! on a value from JSON |
Code
<Nullable>enable</Nullable>
public sealed record CreateUser(string Email, string? DisplayName);
static string Normalize(CreateUser input)
{
if (string.IsNullOrWhiteSpace(input.Email))
throw new ArgumentException("Email is required.", nameof(input));
var email = input.Email.Trim();
var label = input.DisplayName ?? email;
return label;
}
Do not sprinkle ! through a controller to get a green build. Each one is a claim. Request bodies are the place that claim is usually false. Validation of that body is API validation, which is the runtime half of the same rule.
Profile and account fields on Ecom_NET10 are the kind of boundary this shows up on.