Which C# version do I have?
The language version follows the target framework: C# 12 with .NET 8, C# 13 with .NET 9 and C# 14 with .NET 10. A feature marked C# 14 needs <TargetFramework>net10.0</TargetFramework> (and the .NET 10 SDK). Library APIs such as CountBy and Index in LINQ need the matching runtime, .NET 9 here. See the .NET versions page for the full table.
Conventions worth knowing
- Names: PascalCase for types, methods, properties and constants; camelCase for locals and parameters;
_camelCasefor private fields; interfaces start with I; async methods end with Async. - Strings: compare with an explicit
StringComparison(OrdinalorOrdinalIgnoreCasefor identifiers, keys and file names). - async: await all the way down; avoid
.Resultand.Wait(), which can deadlock and hide exceptions; pass aCancellationTokenthrough. - Records vs classes: records for data compared by value (DTOs, messages, value objects), classes for things with identity and behavior (entities, services).
- Collections: expose
IReadOnlyList<T>orIEnumerable<T>, and prefer collection expressions ([]) tonew List<T>()for initialization.
FAQ
What is new in C# 14?
The field keyword for property backing fields, extension members (extension properties and static extension methods in extension blocks), null-conditional assignment (a?.B = c), nameof on unbound generic types (nameof(List<>)), lambda parameter modifiers without types, partial constructors and events, and implicit span conversions. It ships with .NET 10.
What are collection expressions in C#?
A C# 12 syntax for creating collections: int[] a = [1, 2, 3]; List<int> b = [.. a, 4]; The same brackets work for arrays, lists, spans, sets and any type with a collection builder.
When should I use a record instead of a class?
For data compared by value: DTOs, messages and value objects. Records get value equality, a readable ToString, deconstruction and with-expressions for copies.
What is a primary constructor in C#?
Since C# 12 a class or struct can declare constructor parameters after its name, class Service(ILogger logger), and use them anywhere in the class body. They are captured parameters, not properties.
What does required mean on a property?
Since C# 11 a required property must be set in the object initializer, or the code does not compile. Combine it with init for properties that are set once.