I’m going to talk about every single C# 10 features. We will look at them individually with an example.
The top 6 features are listed down.
- Global using directive
- File Scoped Namespace
- Constant Interpolated strings
- Lambda Improvements
- Null Parameter Checking
IDE which I have used for preparing the examples
- Microsoft Visual Studio Community 2022 (64-bit)
- Version: 17.0.5
Global using Directive
This is one of the interesting features. Let’s go ahead and create a Console application in VS 2022 and add the below lines into Program.cs file
using System.Text.Json;
var names = new[] { "Prasad", "Praveen" };
var serialized = JsonSerializer.Serialize(names);
Console.WriteLine(serialized);
This code is perfectly valid in C# 9.0.
Assume that we need to utilize the JsonSerializer.Serialize() method in multiple files under the same project, Till C# 9.0, we have only one option to add the reference System,Text.Json at the beginning of each files. In C# 10, Microsoft has been introduced a new feature to add the reference globally at one place using the keyword “global”. It is recommended to create a separate file which will contain these imports, something like “usings.cs”
C# 10 code would look like below
Program.cs
var names = new[] { "Prasad", "Praveen" };
var serialized = JsonSerializer.Serialize(names);
Console.WriteLine(serialized);
A new file usings.cs will be created and moved all the using imports into it.
Usings.cs
This class file will have only global using System.Text.Json
Assume that I’m going to comment out the line in Usings.cs, if you go back to Program.cs class, you will be getting a compiler error. To resolve this issue, we can edit the project file, and add the <ItemGroup> tags
GlobalUsingDirective.csproj( this is my project file)
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup Condition="'$(ImplicitUsings)'=='true' Or '$(ImplicitUsings)'== 'enable'">
<Using Include="System.Text.Json"/>
</ItemGroup>
</Project>
File Scoped Namespaces
Assume that I have a class file Employee.cs and inside the class, the code looks like below
namespace FileScopedNamespace
{
internal class Employee
{
public string Name { get; set; }
}
}
I’m going to add a new namespace within the same file as below, now my Employee.cs file looks like below since in theory, we can have multiple namespaces in a file.
namespace FileScopedNamespace
{
internal class Employee
{
public string Name { get; set; }
}
}
namespace FileScopedNamespace1
{
internal class Employee1
{
public string Name { get; set; }
}
}
In my 10 years of career in C#, I have never seen such a class file with multiple namespaces. I assume, C# Dev Team also may have same thoughts and what they did, they just removed the pointless nesting of namespace and class and converted into File Scoped Namespace as below
namespace FileScopedNamespace;
internal class Employee
{
public string Name { get; set; }
}
Whatever we are in this Employee.cs file comes under the namespace "FileScopedNamespace;". This is really amazing, and I love this feature.
Constant Interpolated strings
This is another feature which I really like. Assume I have a class like below, I’m trying to apply string interpolation on constant variables.
namespace ConstantInterpolatedString
{
public static class EmailMessages
{
private const string Salutation = "Welcome";
public static class Header
{
public const string SalutionTeamplate = Salutation + " to constant Interpolation";
}
}
}
This can be converted into Constant interpolation as below
namespace ConstantInterpolatedString
{
public static class EmailMessages
{
private const string Salutation = "Welcome";
public static class Header
{
public const string SalutionTeamplate = $"{Salutation} to Interpolation";
}
}
}
Before C# 10, there was no option to apply interpolation on const variables. It will throw the below compiler error
The expression being assigned to EmailMessages.Header.SalutionTemplate must be constant.
Lambda Improvements
Here we will look at some of the lambda improvements.
Previously, we had a function as below
using System;
Func<string> welcome = () => "Welcome to Lambda Improvements";
Console.WriteLine(welcome);
Here we have a func delegate which returns a string.
Note:
Ensure that our language version is pointing to 9.0 in project file as below
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>9.0</LangVersion>
</PropertyGroup>
</Project>
Now let’s change the syntax of func delegate as below
using System;
var welcome = () => "Welcome to Lambda Improvements";
Console.WriteLine(welcome);
You will get an error as below
Feature ‘inferred delegate type’ is not available in C# 9.0. Please use language version 10.0 or greater.
Now, update the language version in project file and see.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>10.0</LangVersion>
</PropertyGroup>
</Project>
The code will work as expected.
Next improvement,
Assume that we have the below code
using System;
//var welcome = () => "Welcome to Lambda Improvements";
var text = () => null;
//Console.WriteLine(welcome);
This will raise exception as below
The delegate type could not be inferred
There is an alternative as below
using System;
//var welcome = () => "Welcome to Lambda Improvements";
Func<string?> test = () => null;
//Console.WriteLine(welcome);
This works fine. However, I want to rewrite this line using var. how? Please see the below syntax
using System;
//var welcome = () => "Welcome to Lambda Improvements";
var text = string? () => null;
//Console.WriteLine(welcome);
This code will build with zero errors.
Null Parameter Checking
In C # 9.0, we can write the null check as below
string? text = null;
SayHello(text);
void SayHello(string message)
{
if(message is null)
{
throw new ArgumentNullException(nameof(message));
}
Console.WriteLine(message);
}
In C# 10.0, we can replace the if condition with below one-liner code
string? text = null;
SayHello(text);
void SayHello(string message)
{
//if(message is null)
//{
// throw new ArgumentNullException(nameof(message));
//}
ArgumentNullException.ThrowIfNull(message);
Console.WriteLine(message);
}
Thank you for reading my article. I will come up with other features in the upcoming articles. Please provide your feedback in the comment box.