C# 14 cheatsheet
C# 14: Records, classes and pattern matching
12 common C# 14 tasks.
Declare an immutable data type
A record gives you value equality, ToString and deconstruction.
public record Person(string Name, int Age);
var ada = new Person("Ada", 36);
Copy a record with changes
Create a modified copy and leave the original unchanged.
var older = ada with { Age = 37 };
Declare a class with a primary constructor
Put constructor parameters on the type declaration and use them in members.
public class Greeter(string name)
{
public string Greet() => $"Hello, {name}!";
}
Require properties at creation
Force callers to set a property, and make it settable only during initialization.
public class User
{
public required string Email { get; init; }
public string? Nickname { get; set; }
}
Customize an auto-property
C# 14: use the field keyword to reach the compiler-generated backing field.
public string Name
{
get;
set => field = value.Trim();
} = "";
Choose a value with a switch expression
A compact switch that returns a value, with a default.
string label = score switch
{
>= 90 => "A",
>= 80 => "B",
_ => "C"
};
Test and unpack a type
Check a type and bind it to a variable in one expression.
if (shape is Circle { Radius: > 10 } c)
Console.WriteLine(c.Radius);
Match the shape of a list
Match arrays and lists by length and contents.
var result = numbers switch
{
[] => "empty",
[var only] => $"one: {only}",
[var first, .., var last] => $"{first}..{last}"
};
Define an enum
A named set of constants, and parsing one from text.
enum Status { Draft, Published, Archived }
var status = Enum.Parse<Status>("Published");
Add a method to an existing type
A static method in a static class, with this on its first parameter.
public static class StringExtensions
{
public static bool IsBlank(this string? s) => string.IsNullOrWhiteSpace(s);
}
Constrain a generic type
Require that a type argument has certain capabilities.
T Max<T>(T a, T b) where T : IComparable<T>
=> a.CompareTo(b) >= 0 ? a : b;
Provide a default interface method
An interface can include an implementation that classes may override.
public interface ILogger
{
void Log(string message);
void Info(string message) => Log($"INFO: {message}");
}