.Net is constantly evolving, a new version comes out every year, and it's easy to lose track of some of the useful changes.
I compiled a list of 7 (mostly) recent features that I from my code reviews I think get overlooked by devs (or devs' AI tools).
1. Extension Members (C# 14)
In addition to extension methods, we can now add extension properties and static methods to a type.
Properties are mostly just for readability, and static extension methods are useful for writing factory methods instead of creating a separate factory class.
So instead of
public static class CustomerExtensions
{
public static bool IsPayingCustomer(this Customer customer)
{
return customer.TotalSpent > 0;
}
}
we can write
public implicit extension CustomerExtensions for Customer
{
// Add a property to a class you don't control
public bool IsPayingCustomer => this.TotalSpent > 0;
// Add a static method
public static Customer Parse(string json)
=> JsonSerializer.Deserialize<Customer>(json);
}
No state or memory, just syntactic sugar for better readability. In the background the property is still an extension method.
var customer = Customer.Parse("{\"TotalSpent\": 100}");
var oldMethod = customer.IsPayingCustomer();
var newProperty = customer.IsPayingCustomer;
2. The field keyword (C# 14)
It isn't required anymore to define a backing field to have some logic in getter/setter.
Just use the field keyword (be careful not to name anything 'field' in the class) and get the implicit backing field.
public string Name
{
get => field;
set => field = value?.Trim();
}
3. File-based apps (.NET 10)
Do you have a console solution (or several) just for various small tools?
Now instead we can just run a single .cs file with dotnet run mytool.cs, without the need for any .sln or .csproj.
Write your single file like
// Add nuget packages with the special syntax
#:package Newtonsoft.Json@13.0.3
// Still need to add using statements
using Newtonsoft.Json;
// Access command line arguments
var allArgs = Environment.GetCommandLineArgs();
4. OrderedDictionary<TKey, TValue> (.NET 9)
We now have a kind of a named list in shape of OrderedDictionary<TKey, TValue>.
The elements can be both accessed by key and by index.
var laundryRoom = rooms[17];
var diningRoom = rooms["dining"];
The order of elements is the order of insertion, so 0 is the first inserted element.
5. Enumerable.Index() (.NET 9)
A tiny but sweet sugar: instead of writing a for loop
for (int i = 0; i < items.Count; i++)
{
var item = items[i];
// act
}
we can use foreach with IEnumerable and still get the index variable:
foreach (var (index, item) in items.Index())
{
// act
}
6. CountBy and AggregateBy LINQ (.NET 9)
Another sweet addition:
// old count of items by status
var countByStatus = items.GroupBy(x => x.Status)
.Select(g => new { g.Key, Count = g.Count() });
// new
var countByStatus = items.CountBy(x => x.Status);
// old sum of amounts by status
var aggregateByStatus = items.GroupBy(x => x.Status)
.Select(g => new { g.Key, Sum = g.Sum(x => x.Amount) });
// new
var aggregateByStatus = items.AggregateBy(
x => x.Status, // Key selector
seed: 0m, // Initial value
(sum, x) => sum + x.Amount // Aggregation logic
);
Apart from just being more readable, these methods skip the intermediate grouping allocation.
7. CompareOptions.NumericOrdering (.NET 9)
Finally we can sort string and have "file2" come before "file10", thanks to CompareOptions.NumericOrdering:
var sorted = myStrings.OrderBy(s => s,
StringComparer.Create(CultureInfo.InvariantCulture,
CompareOptions.NumericOrdering));
That's my list. Do you know other features people should use more often?

























