C# 10 has been available since November 2021. In this blog, I come back to some of the new features that it brought us, in addition to the last video of the channel. Good reading!
First of all, as a reminder, the video we published last week to demonstrate some of the new features of C# 10:
Usings implicit
The usings implicit are there to allow us to have a better visibility at the level of our classes, by making an automatic import of everything that is part of the framework used in our project. For example, bookstores that are part of Microsoft.NET.Sdk for a console project will be automatically imported and we will no longer need to import them into our classes. To see the list of namespaces included for the different SDKs, you can consult this item.
We can also manually specify certain exclusions, for example if the name of a class would conflict with a class in our project. To do this, just add a ItemGroup in our project file and include the element there Using with the attribute corresponding to our need:
Usings global
The usings global are intended as a complement to usings implied. By prefixing a using
keyword global
, we end up importing this namespace for our whole project. My favorite example for this use is in our test projects. All our test classes will contain certain usings that come up systematically. On the other hand, by adding a file which will contain this:
global using FluentAssertions; global using Moq; global using Xunit;
We just eliminate these 3 imports of all our project files. When we spoke of improved readability, this removes the "noise" that these 3 lines make in each of these classes.
File-scoped namespaces
Another cool feature that C# 10 brings us is the ability to have single scoped namespaces for our file. So instead of having a namespace with braces, which brings a level of indentation to everything inside, we end up with this instead:
namespace CSharp10; public class Person {public Guid Id {get; set; } public string Name {get; set; } = string.Empty; public Address Address {get; set; } = new Address (); }
We therefore gain a better use of horizontal space by reducing the indentation of our files and better readability.
Natural types for lambdas
Before C# 10, declaring a lambda implied defining its full type, for example Func
. Now type inference is possible so we can simply declare our lambda with the keyword var
. We can also apply the same use to a method without parameters, if this one does not have several overloads. So this becomes something possible to do:
var read = Console.Read;
Structures
In terms of structures, one of the biggest changes is the fact that we can now have them of type record. This brings several interesting aspects. The first is that you can declare a structure positionally, like this:
public readonly record struct Point (double X, double Y);
Another thing to notice in this statement is the use of the keyword readonly. In the context of a structure, this will have the effect of creating the properties so that they are immutable, in the same way as if we had declared the property with get and init. If we prefer the long version, we can also do it via a more conventional declaration, since we can now have an empty constructor and an initialization on the properties:
public record struct Point {public Point () {} public Point (double x, double y) {X = x; Y = y; } public double X {get; init; } = 0; public double Y {get; init; } = 0; }
Expressions with on anonymous types
It is now possible to use the expressions with on anonymous types, in the same way as on a record. With this, this code allows us to more easily declare new variables when working with anonymous types:
var person = new {Age = 1, Name = "Test"}; var person2 = person with {Age = 2};
Improvements to interpolated strings
An improvement that seems small, but which could make our life much easier is in the interpolated string. It is now possible to declare interpolated constants, versus before we could only on one variable. This can for example allow us to declare constants for our API routes:
public static class ApiRoutes {private const string BasePath = "/ api"; public const string WeatherForecast = $ "{BasePath} / forecast"; }
Or to directly use the name of a class with nameof in attributes, like this:
[Obsolete ($ "Use {nameof (NewEntity)} instead")]
Conclusion
As with the video, this was just a summary of some of the new features in C# 10. We haven't talked about the static abstract members which are available in preview, which may become a very interesting feature in the future of C#. For the full list of changes, do not hesitate to consult the documentation on this subject.
In your daily use, what is THE feature that interests you the most from C# 10? And is there something you would like to see covered in more detail, either in a new blog or video? Please let me know in the comments!
Bruno