C# 10 Implicit Using and File-Scoped Namespaces

iphone, computer, work, screen, apple, typing, man, person, technology, coding, conversation, programming, programmer, macbook air, design, freelancer, devices, notes, editing, mockup, coder

"A good developer is a lazy developer, but the inverse is not always true"

With .NET 6 comes C# 10, and this has a couple of interesting language features. Here I want to discuss working with namespaces.

Implicit Using Namespaces

Don't you hate it when each class in your project starts with a bunch of using statements?

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ...

And to get these usings up there, you first need to know which classes you will be using, and then you add the using statement using a proper editor. For example, with Visual Studio I write the name of the class, then press Ctrl+. to add the using. Neat, but I still lose time with this.

With the new C# 10 implicitly using namespaces you can add a single file containing the namespaces you need in your application. Then each class will automatically add a using statement for each global using namespace.

This means that adding a new class to your project will already have these usings, giving you proper intellisense without first having to add the usual using statements!

global using System;
global using System.Collections.Generic;
global using System.Threading.Tasks;

It is recommended that you place all your global usings in a single file, and the name of this file does not matter, but I prefer to name it Imports.cs (matching razor _Imports).

Global Usings and ASP.NET

Create a new ASP.NET project using .NET 6, and look at Program.cs. Using the new minimal API you will see that this is also uses global usings. But where is the file containing these global usings? There is none?!

var builder = WebApplication.CreateBuilder(args);

Look a little closer at your project in Visual Studio. There is an Imports section containing an Sdk.props file, which contains the following:

<ItemGroup Condition="'$(Language)' == 'C#' AND ('$(ImplicitUsings)' == 'true' or '$(ImplicitUsings)' == 'enable')">
  <Using Include="System.Net.Http.Json" />
  <Using Include="Microsoft.AspNetCore.Builder" />
  <Using Include="Microsoft.AspNetCore.Hosting" />
  <Using Include="Microsoft.AspNetCore.Http" />
  <Using Include="Microsoft.AspNetCore.Routing" />
  <Using Include="Microsoft.Extensions.Configuration" />
  <Using Include="Microsoft.Extensions.DependencyInjection" />
  <Using Include="Microsoft.Extensions.Hosting" />
  <Using Include="Microsoft.Extensions.Logging" />
</ItemGroup>

Before you start adding your own namespaces to this file, do realize that this is a global file, located in C:\Program Files\dotnet\sdk\6.0.*\Sdks\Microsoft.NET.Sdk.Web\Sdk. And messing it up will stop all your builds using the Microsoft.NET.Sdk.Web SDK. It even contains a warning:

***********************************************************************************************
Sdk.props

WARNING:  DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
          created a backup copy.  Incorrect changes to this file will make it
          impossible to load or build your projects from the command-line or the IDE.

Copyright (c) .NET Foundation. All rights reserved.
***********************************************************************************************

Enabling or Disabling Global Namespaces

When you create a new project in .NET 6 you will automatically have the implicit namespaces enables, but for existing projects you will have to enable this yourself.

Inside your project you can enable (or disable) implicit using namespaces with this project setting:

<ImplicitUsings>enable</ImplicitUsings>

File-Scoped Namespaces

If you don't like typing curly braces, you will like file-scoped namespaces. Most of the time a .cs file contains a single class, which belongs to a single namespace.

namespace SomeNamespace
{
  public class SomeClass
  {
  }
}

So why do we need to curly braces around the class? We could just as easily write:

namespace SomeNamespace;
public class SomeClass
{
}

Now we can do this with C#, and it is called file-scoped namespaces.

Special cases

You might wonder if it is allowed to have more than one file-scoped namespace? For example:

namespace A;
namespace B; // ERROR
namespace C; // ERROR

internal class Nesting
{
}

So this is not allowed, if you want to nest namespaces you can use a single file-scoped namespace:

namespace A.B.C;

internal class Nesting
{
}

Or can you mix normal and file-scoped namespaces? The answer is: NO!

namespace A;

namespace B.C // ERROR
{
  internal class Nesting
  {
  }
}