"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 using
s, 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
{
}
}