Chapter 10 Smorgasbord Of Features For Concise Code
2 min read- Chapter 10 — A smörgåsbord of features for concise code
- 10.1 Using static directives
- 10.2 Object and collection initializer enhancements
- 10.2.1 Indexers in object initializers
- 10.2.2 Using extension methods in collection initializers
- 10.2.3 Test code vs production code
- 10.3 The null-conditional operator (`?.`, `?[]`)
- 10.3.1 Simple and safe dereferencing
- 10.3.2 More detail (mental model)
- 10.3.3 Boolean comparisons
- 10.3.4 Indexers
- 10.3.5 Working effectively
- 10.3.6 Limitations
- 10.4 Exception filters (`catch (...) when (...)`)
- 10.4.2 Retrying operations
- 10.4.3 Logging as a side effect
- 10.4.4 Case-specific filters
- 10.4.5 Why not just throw?
Chapter 10 — A smörgåsbord of features for concise code
Purpose of this chapter: learn several features that improve day-to-day readability by removing noise: using static, initializer enhancements, the null-conditional operator, and exception filters.
10.1 Using static directives
using static imports the static members of a type, so you can omit the type name:
using static System.Math;
var radians = degrees * PI / 180;
var x = Cos(radians) * magnitude;
When it helps:
- Math-heavy code.
- Working with enum flags (reducing repetition).
When it hurts:
- If it makes the origin of members unclear or introduces name collisions.
10.2 Object and collection initializer enhancements
These features reduce ceremony when building objects and collections.
10.2.1 Indexers in object initializers
When a type has an indexer, you can set entries inline:
- Great for dictionaries and similar “keyed” objects.
10.2.2 Using extension methods in collection initializers
Collection initializers can work with Add methods, including extension methods, which can make certain builder patterns more fluent.
10.2.3 Test code vs production code
Guideline:
- Initializers are fantastic in tests and setup code.
- In production paths, be careful that “clever” initialization doesn’t hide complexity or errors.
10.3 The null-conditional operator (?., ?[])
Null-conditional operators let you safely dereference:
var city = customer?.Address?.City;
var first = list?[0];
10.3.1 Simple and safe dereferencing
Use it to reduce defensive if (x != null) ladders when “missing data” is acceptable.
10.3.2 More detail (mental model)
It short-circuits:
- If the receiver is null, the whole expression becomes null (or default for nullable value contexts).
10.3.3 Boolean comparisons
A common gotcha:
x?.Flag == trueis a safe way to check a nullable bool-like result.
10.3.4 Indexers
?[] works similarly for indexers:
- Useful when the collection itself can be null.
10.3.5 Working effectively
Guideline:
- Use it when null is an acceptable outcome.
- Don’t use it to hide a bug where null is unexpected; fail fast instead.
10.3.6 Limitations
- It’s not a replacement for correct invariants.
- It can obscure where null originated if overused; keep expressions readable.
10.4 Exception filters (catch (...) when (...))
Exception filters let you decide whether to catch based on a condition:
catch (HttpRequestException ex) when (IsTransient(ex))
{
// retry / fallback
}
Why they matter:
- You can filter without catching-and-rethrowing (keeps cleaner stack traces and intent).
10.4.2 Retrying operations
Filters help with “catch only transient errors” while letting non-transient errors bubble.
10.4.3 Logging as a side effect
You can log in the filter expression (carefully):
- It can reduce duplicated try/catch blocks.
- Don’t make filters expensive or stateful in surprising ways.
10.4.4 Case-specific filters
Filters let you keep exception handling precise:
- “Handle only when the error code matches X” rather than catching everything.
10.4.5 Why not just throw?
Throwing after catching is often worse:
Use filters or let exceptions propagate when you’re not meaningfully handling them.
- It can hide intent, alter stack traces, and complicate debugging.