Reading — step 1 of 6
Learn
C# 8 introduced nullable reference types — making nullability part of the type system. Like Kotlin or TypeScript's null safety, this catches whole classes of NullReferenceException bugs at compile time.
Enabling NRT
In .csproj:
<Nullable>enable</Nullable>
Or per-file:
#nullable enable
With NRT enabled, string means "non-null string," and string? means "nullable string."
The basic distinction
string name = null; // ⚠ warning — can't assign null to non-nullable
string? maybeName = null; // ✓ OK — nullable
string g = maybeName.ToUpper(); // ⚠ warning — possible NullReferenceException
The compiler tracks whether each value might be null. Calling methods on something string?-typed without checking is a warning.
Null-conditional and null-coalescing
string? maybeName = GetName();
int? len = maybeName?.Length; // null if maybeName is null
int length = maybeName?.Length ?? 0; // default if null
// Throw on null:
string nonNull = maybeName ?? throw new ArgumentException("name required");
// Null-forgiving operator (use sparingly — promises non-null to the compiler)
int forced = maybeName!.Length; // suppresses the warning
The ! operator says "trust me, this isn't null." It does NOT add a runtime check — if you're wrong, you crash.
Null-checking and flow analysis
After you check, the compiler narrows the type:
string? name = GetName();
if (name != null)
{
Console.WriteLine(name.Length); // ✓ no warning — narrowed to non-null
}
// Also works:
if (name is null) return;
Console.WriteLine(name.Length); // ✓ narrowed
// And:
name ??= "default";
Console.WriteLine(name.Length); // ✓ guaranteed non-null after ??=
Nullable annotations on parameters
public void Greet(string name) // parameter must not be null
public void Greet(string? name) // null is acceptable
public User? FindUser(int id) // result might be null
public User FindUser(int id) // result guaranteed non-null
The annotations document intent AND let the compiler enforce it.
Generic constraints
public T? FirstOrDefault<T>(IEnumerable<T> items)
where T : class // T is a non-nullable reference type → T? makes sense
{
foreach (var item in items) return item;
return null;
}
On this platform's grader (C# 7)
The string? annotation and #nullable enable are C# 8 — our grader runs Mono's C# 7 compiler, where they won't compile. In C# 7 every reference type is implicitly nullable (exactly the problem NRT was invented to fix!), so your exercise handles a plain string that may be null. The guard tools are identical in C# 7: string.IsNullOrWhiteSpace, ??, and ?..
Common mistakes
- Sprinkling
!everywhere to silence warnings — defeats the purpose. Treat!like a TODO. - Forgetting that
T?for value types isNullable<T>— for int,int?isNullable<int>, a different type. For reference types it's just an annotation. - Mixing nullable and non-nullable code — start with
<Nullable>enable</Nullable>for new code; use#nullable enableper-file in existing code. - Trusting external libraries' annotations blindly — sometimes wrong; prefer defensive checks at API boundaries.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…