It's dangerous to code alone! Take this.

What's New in C# 10?

What’s New in C# 10?

C# 10, .NET 6, and Visual Studio 2022 are all set to launch in November of 2022. In this article, I’m going to cover the most important things happening in C# 10. This isn’t comprehensive; it covers the things I’m most excited about or that I think will have an impact on how most people write C# code.

Note that this is through the lens of The C# Player’s Guide, which is what this site is about.

1. Top-level statements are the default.

In the 4th Edition, right at the beginning, I say, “The template for a new console project adds this whole class Program and public static void Main thing. But go ahead and delete all of that and replace it with a simple System.Console.WriteLine("Hello, World!");.” This shorter style is officially called “top-level statements.”

With .NET 6 and Visual Studio 2022, the template uses top-level statements. You will no longer need to delete all that public static void Main stuff!

Importantly, this means that this simpler style is about to become much more common. If you haven’t been using it, now is the time to get comfortable with it!

2. Global using Directives

You can now apply the global keyword to a using directive to apply it in all files in a project automatically: global using System;.

I recommend placing them somewhere easy to find–maybe a GlobalUsings.cs file or a ProjectSettings.cs file, instead of sprinkled across arbitrary .cs files.

I also recommend using them sparingly. Only use a global using directive if the overwhelming majority of your files use the namespace. It has a tendency to clutter your scope with random names, and obscures the fact that a given namespace is in use. Only use them when the usage of those namespaces are already obvious.

3. New projects automatically include several common using directives.

Given the item above, you might be thinking, “I’m going to put a global using System; in all of my projects!” That would make sense, given the fact that virtually everything is using the System namespace. But you don’t need to!

New .NET 6 projects have a setting on by default that automatically includes a set of using directives automatically, including the following:

  • System
  • System.Collections.Generic
  • System.IO
  • System.Linq
  • System.Net.Http
  • System.Threading
  • System.Threading.Tasks

I honestly think 99% of all of the code and challenges in the book use those namespaces and nothing more. That means you could do just about everything in the book without having a single using directive in any of your code.

That doesn’t mean namespaces and using directives aren’t important and valuable. You’ll still need to understand them. But that pile of using directives in each of your files just got culled down to only namespaces that aren’t obvious, making that section of your code useful instead of cluttered!

4. File-Scoped Namespace Declarations

In the past, when you’ve stated what namespace your types are in (assuming you want them somewhere besides the global namespace) you needed to put them in a namespace block:

namespace SomeNamespace
{
    class SomeClass
    {

    }
}

In C# 10, you can do this:

namespace SomeNamespace;

class SomeClass
{

}

This removes a level of indentation, making your code simpler and easier to understand.

5. Nullable Reference Warnings On by Default

In C# 8 and earlier, when you use a reference type like string, null was always an option, but it was not obvious if any particular usage should expect null to be a real possibility or not.

In C# 9, you could go out of your way to change some settings so that string implied null is not meant to be a legal option and string? (with the question mark) to indicate that null miight be an option.

In C# 10, with the new project templates, this setting is on by default, instead of you needing to specifically enable it. With it on, you will get compiler warnings any time a type that doesn’t expect null is assigned a potential null value. You will also get compiler warnings any time you use something that might be null without first checking for null.

Given how often people end up with NullReferenceExceptions, this change should help you catch a whole lot of potential bugs before it affects some poor user.

You can turn if off if you want, but I recommend keeping it on.

The biggest catch, here, is that most of the code you find online will likely be using the old style, where string doesn’t tell you much about if null might be an option or not, even though in your code it will mean null shouldn’t be an option. Stated differently, you might see something like this online:

string input = null;

In this case null is definitely expected. But if you copy and paste that into your own new project, you’ll get a compiler warning because string means “this shouldn’t be null”. You’ll have to mentally judge, from all code you find online, whether null was meant to be an option or not. (To be fair, you always had to do that. Now it will stand out more, and force you to recon with it.)

6. Nested Property Patterns

Nested property patterns got a little simpler. Instead of this:

{ Property1: { Property2: { Property3: 0 } } }

You can do this:

{ Property1.Property2.Property3: 0 }

7. Generic Attributes

Attributes can now include generic type parameters. The 4th edition doesn’t specifically call out the fact that attributes couldn’t be generic, because that’s a combination of two somewhat advanced features, so it doesn’t have any immediate impact on the book, but it is a nice small enhancement.

8. Lambda Return Types

One key benefit of lambda expressions is their conciseness: collection.Where(n => n % 2 == 0). The compiler infers a lot of stuff from the context–the type of the argument, the return type, etc. Earlier versions of C# let you specify parameter types when needed, and with C# 10, you can also specify the return type for the rare times where you have a need:

collection.Where(bool (n) => n % 2 == 0)

9. Parameterless Struct Constructors and Field Initializers

In earlier versions of C#, you could not define parameterless constructors for a struct, nor could you define initializers for struct fields. With C# 10, you’re able to do both. Just keep in mind that, due to the nature of structs as value types, it is still possible to get a struct value without ever calling your constructor.

10. Record Structs

C# 9 introduced records, which let you use an extremely compact notation for defining a class that was data-focused.

Well apparently, structs got jealous of this notation, and C# 10 added the same syntax for structs:

public record struct Point(float X, float Y);

That code will create a value type (a struct), with all of the syntax benefits (and auto-generated code) of a record. (You can now also make a record class which has the same meaning as a plain old record, if you feel the need to differentiate the two more clearly.)

11. Hot Reload

Visual Studio 2022 has a new, awesome feature called Hot Reload that lets you edit code and apply it, even without being at a breakpoint. This is a huge improvement over the Edit and Continue feature that has been around for a while. The one catch that I’ve seen is that it won’t apply the updated code to any currently running instance of the method. You’ll have to wait until it is called to see the changes.

More!

There are several other small things in C# 10, but that’s those are the most notable ones. C# 10 is an exciting update to the language, and it will be fun to see what the future holds!