Hi all. Been a while since I’ve done one of these. Thanks for continuing to subscribe! And if you’d like this post in cringe Youtube video form, check out:
1. Null-Conditional Assignment (?=
)
We've all written this boilerplate code a thousand times. You have a nullable object, and you only want to assign a value to one of its properties if the object itself isn't null
.
Before: C# 13
You had to perform an explicit null check.
public class Channel
{
public int Subscribers { get; set; }
public int Members { get; set; }
}
// ---
Channel? myChannel = null; // or new Channel();
// We have to check for null before assigning
if (myChannel is not null)
{
myChannel.Subscribers = 1000;
}
After: C# 14
With the new null-conditional assignment operator (?=
), you can do this in a single, safe, and readable line.
C#
Channel? myChannel = null;
// This will only assign 1000 if myChannel is not null
myChannel?.Subscribers = 1000;
It's a small change, but a very welcome one!
2. The field
Keyword for Semi-Auto-Properties
Auto-properties are great, but as soon as you need to add logic to your getter or setter (like validation), you have to convert it to a full property with an explicit private backing field.
Before: C# 13
This required creating a separate field (_subscribers
) just to add a check in the setter.
C#
public class Channel
{
private int _subscribers;
public int Subscribers
{
get => _subscribers;
set
{
if (value < 1000)
{
throw new ArgumentException("Not enough subs!");
}
_subscribers = value;
}
}
}
After: C# 14
The new field
keyword gives you access to the implicit, compiler-generated backing field of an auto-property. This means you can add logic without the boilerplate!
C#
public class Channel
{
public int Subscribers
{
get => field; // 'field' refers to the implicit backing field
set
{
if (value < 1000)
{
throw new ArgumentException("Not enough subs!");
}
field = value; // Assign to the implicit backing field
}
}
}
This keeps the code much cleaner and more concise.
3. User-Defined Compound Operators
This one is really cool. Have you ever wanted to define what a compound operator like ++
or +=
does for your own custom type? Now you can!
Imagine we want the ++
operator to increment both the Subscribers
and Members
properties of our Channel
class at the same time.
Before: C# 13
You'd have to increment each property manually.
C#
var myChannel = new Channel();
myChannel.Subscribers++;
myChannel.Members++;
After: C# 14
You can now overload the compound operator directly in your class definition.
C#
public class Channel
{
public int Subscribers { get; set; }
public int Members { get; set; }
// Define what the ++ operator does for a Channel
public static Channel operator ++(Channel c)
{
c.Subscribers++;
c.Members++;
return c;
}
}
// ---
var myChannel = new Channel();
myChannel++; // This now increments both Subscribers and Members!
Console.WriteLine($"Subs: {myChannel.Subscribers}, Members: {myChannel.Members}");
// Output: Subs: 1, Members: 1
Not sure where I’d use this but hey ho!
4. The extension
Keyword
Extension methods have always required a public static
class and public static
methods using the this
keyword. C# 14 introduces a new, more explicit syntax.
Before: C# 13
The classic syntax we all know.
C#
public static class ChannelExtensions
{
public static void PrintDetails(this Channel c)
{
Console.WriteLine($"Subs: {c.Subscribers}, Members: {c.Members}");
}
}
After: C# 14
You can now use the extension
keyword to create an "extension type." The syntax is cleaner and makes the intent clearer.
C#
public extension ChannelExtensions
{
public void PrintDetails(this Channel c)
{
Console.WriteLine($"Subs: {c.Subscribers}, Members: {c.Members}");
}
}
Personally, I'm not totally sold on this one yet, as it just creates another way to do the same thing. But it's clearly a direction the language is heading, so it's good to know!
5. nameof
Improvements for Generics
The nameof
operator is a handy tool for getting the string name of a variable, type, or member. However, it had a limitation with generic types.
Before: C# 13
nameof
worked on a constructed generic type, but not on an "unbound" or open generic type.
C#
public class Channel<T> { }
public class YouTube { }
// This worked fine
Console.WriteLine(nameof(Channel<YouTube>)); // Output: Channel
// This caused a compile error
// Console.WriteLine(nameof(Channel<>));
After: C# 14
This limitation has been removed. You can now use nameof
directly on an unbound generic type.
C#
// Now this works perfectly!
Console.WriteLine(nameof(Channel<>)); // Output: Channel
This is a nice little fix for those edge cases where you need the name of the generic type definition itself.
My thoughts on C# 14
Actually they’ve been quite restrained this year. No crazy new ways to instantiate lists or classes that conceptually forks C#. I do get alot of comments on my channel saying that C# is getting too complicated, so glad they have shown restraint. Well done chaps!