crispbyte.dev-content.git

git clone https://git.crispbyte.dev/crispbyte.dev-content.git

crispbyte.dev-content.git / content / blog
cheddar  ·  2025-08-29

2025-05-09-New_CS_Patterns.md

 1---
 2date: 2025-05-09
 3title: New C# Patterns
 4---
 5One of the reasons I like C# is that it is a constantly evolving language. There are always new patterns emerging that make things just a little easier, just a little more fun. Here's two that I like that I've learned recently.
 6
 7## Simpler null checks
 8This one is a new-ish way to do null checks. Let's say you have this model:
 9```cs
10public class Book
11{
12  public string? Description { get; set; }
13}
14```
15
16With code something like this:
17```cs
18Book? book = GetBookByTitle(title);
19```
20
21You want to do something with the description, but of course only if there is a description to work with. An older way to do this might be:
22
23```cs
24if (book?.Description != null)
25{
26  var description = book.Description;
27
28  // Use the description
29}
30```
31
32But because pattern matching works in `if()`, we can do this instead:
33```cs
34if (book?.Description is { } description)
35{
36  // Use the description
37}
38```
39
40That empty `{ }` pattern will match any value that is not null. You can combine it with a declaration all in one statement.
41
42## (Semi-)implicitly typed collection expression
43If you use implicit type declarations, you probably write something like this at times:
44```cs
45var bookList = new List<Book> { new(...) };
46```
47
48Collection expressions are a nice short way of creating collections. If you want to instantiate a list using a collection expression this is one way of doing it:
49```cs
50List<Book> bookList = [new(...)];
51```
52
53But what if you really really want to keep your implicit type declarations? This won't work since the compiler has no idea what the target type should be:
54```cs
55var bookList = [new(...)];
56```
57
58If you use this, it will work again:
59```cs
60var bookList = (List<Book>)[new(...)];
61```
62
63That looks like casting, but what are we even casting? What's going on here? What's the benefit? It saves a few characters but is it worth using a construct that looks so strange and feels so wrong?
64
65_Note: This is as of .NET 9. Future behavior can obviously change._
66
67Yes it is. At least for lists, it turns out that `(List<T>)[]` is faster than `new List<T> { }`. For nano-second scale levels of faster. Even better, if you can use `(IReadOnlyCollection<T>)[]` it's a little faster still.
68
69Trust me. If you use this style long enough, it starts to look normal.