Dotnet logo

.NET Tools

Essential productivity kit for .NET and game developers

.NET Tools How-To's

Global Usings – A Look at New Language Features in C# 10

ReSharper and Rider support for C# 8

Welcome to the third part of our series, where we take a closer look at the new C# language features the .NET team has implemented, and how ReSharper and Rider make it easy to adopt them in your codebase. Welcome to C# 10 and .NET 6!

In this series, we are looking at:

In this post we will look at the different ways the new global usings can help. Psst! ReSharper and Rider support them both. Now, have fun and be amazed!

Global Usings

How many times does your codebase contain the lines using System or using System.Linq? Among individual other namespaces, some are just very common to import in every file throughout your solution. At the same time, it can be very annoying if your file templates don’t have these included and you have to import them over and over again.

With C# 10 you can use global using directives that the compiler will consider for the whole project:

// GlobalUsings.cs
global using System;

// Program.cs (no usings)
Console.WriteLine("Hello World");

You can even go one step further, and define a GlobalUsing.Tests.cs with all the test-relevant namespaces, and create a Directory.Build.props in the root of your repository. This will let those namespaces be automatically imported in every project ending with the Tests postfix:

<Project>

    <ItemGroup Condition="$(MSBuildProjectName.EndsWith('Tests'))">
        <Compile Include="GlobalUsings.Tests.cs" />
    </ItemGroup>

</Project>

If you’re looking for a great test assertion library, remember, we had a great OSS PowerUps session with Dennis Doomen about Fluent Assertions!

Global usings also work in other variations, such as static usings and using aliases, which makes them really convenient to use the Math static class in computational code or to replace commonly used types with better implementations:

// GlobalUsings.cs
global using static System.Math;
global using Console=Spectre.Console.AnsiConsole;

// Program.cs
var max = Max(arg1, arg2);
Console.MarkupLine($"[bold]Max input:[/] {max}");

Just as with any other using directive, ReSharper and Rider will highlight any unused global using directive, so that you can keep your code clean and minimal:

Remove redundant Global Using Directive

There is also a new project-level property called ImplicitUsings to add a set of common namespaces that depend on the SDK chosen in your project. For instance, when using Microsoft.NET.Sdk, you’ll get the following namespaces imported:

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

In contrast to the previous GlobalUsings.cs file, these global imports work on the MSBuild project level. And very good news – you can define custom global usings via MSBuild, too! Getting back to our example with test namespaces from before, we could adapt our Directory.Build.props to have the relevant infrastructure in a single place:

<Project>

    <ItemGroup Condition="$(MSBuildProjectName.EndsWith('Tests'))">
        <PackageReference Include="FluentAssertions" Version="6.1.0" />
        <Using Include="FluentAssertions" />
    </ItemGroup>

</Project>

You can also define the additional attributes Static (boolean) and Alias (string) to fully mimic a real using directive:

<Project>
    <ItemGroup>
        <Using Include="System.Math" Static="True" />
        <Using Include="Spectre.Console.AnsiConsole" Alias="Console" />
    </ItemGroup>
</Project>

As a library author, you should respect your user’s configuration and only add global usings in the <package-id>.props file when the ImplicitUsings property is enabled. As a library user, you can manually remove unwanted namespaces without disabling the feature completely:

<Project>

    <ItemGroup>
        <PackageReference Include="Package.With.UnwantedNamespace" />
        <Using Remove="UnwantedNamespace" />
    </ItemGroup>

</Project>

Since it’s not immediately obvious, which package reference globally imports additional namespaces, we are looking forward to – maybe – get a first-class attribute on PackageReference items. Feel free to upvote the issue!

Download ReSharper 2021.3 EAP or check out Rider 2021.3 EAP to start taking advantage of C# 10 in the best possible way. We’d love to hear your thoughts!

image description