Namespaces implicites (C# 10)

Cet article fait partie d’une série d’articles sur les apports fonctionnels de C# 10.0.

A partir de C# 10 et .NET 6, 2 fonctionnalités permettent de limiter la répétition des using <namespace> en tête des fichiers C#:

  • l’opérateur global et
  • la propriété ImplicitUsings.

Ces 2 fonctionnalités visent à déclarer les namespaces une fois par projet de façon à ne pas avoir à répéter les déclarations dans tous les fichiers .cs.

Mot-clé global

A partir de C# 10, le mot-clé global a désormais 2 significations:

  • Utilisé en tant que mot-clé de cette façon global:: il est un alias pour désigner le namespace global par opposition à un namespace déclaré par le développeur dans son code. Le namespace global contient des types qui ne sont pas déclarés dans un namespace nommé. global:: permet de différencier 2 namespaces qui auraient le même nom et dont un des 2 ferait partie de code déclaré en dehors du code du développeur.

    Par exemple, si on considère le code suivant:

    namespace CS10_Example.System
    {
      public class Object
      {  }
    }
    

    On peut utiliser cette classe de cette façon:

    namespace CS10_Example
    {
      internal class GlobalKeywordExample
      {
        public void ExecuteMe()
        {
          var exampleInstance = new System.Object();
        }
      }
    }
    

    System.Object désigne la classe CS10_Example.System.Object. Si on veut instancier l’objet Object provenant du framework, on ne peut pas le faire sans passer par le mot-clé global:

    var exampleInstance = new System.Object();
    var objectInstance = new global::System.Object();
    

    Dans cet exemple global::System.Object désigne bien l’objet object du framework.

  • A partir de C# 10, global est aussi utilisé en tant que modificateur de portée lorsqu’on déclare des namespaces. Lorsque global précède une déclaration using <namespace>, il permet d’étendre la portée de la déclaration à la portée du projet.
    Ainsi si on déclare l’utilisation d’un namespace dans un fichier, en faisant précéder la déclaration avec global, la déclaration aura pour portée le projet:

    global using CS10_Example.System;
    

    On peut aussi déclarer de façon globale des alias avec une syntaxe du type:

    global using Env = System.Environment;
    

    L’intérêt est d’éviter de multiplier les déclarations des mêmes namespaces dans plusieurs fichiers .cs du projet. Une seule déclaration suffit.

Propriété ImplicitUsings

ImplicitUsings est une propriété du .csproj qui est apparu à partir de .NET 6 qui permet d’ajouter des déclarations globales de namespace dans un .csproj en fonction du type de projet créé. Si la propriété est activée, alors à la compilation, des déclarations du type suivant seront rajoutées:

global using global::<namespace du framework>;

Ces déclarations ont pour but d’éviter la multiplication des using <namespace> dans chaque fichier d’un projet.
Dans la pratique suivant le type du projet, les déclarations sont rajoutées dans un fichier se trouvant dans:

<répertoire du projet>\obj\<configuration>\<target framework>\<nom du projet>.GlobalUsings.g.cs

Par exemple si le projet s’appelle Cs10Example, que la configuration de compilation soit Debug et que le framework cible net6.0 alors le fichier sera:

Cs10Example\obj\Debug\net6.0\Cs10Example.GlobalUsings.g.cs

Le contenu de ce fichier dépend du type de projet indiqué dans le .csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">
  ...
</Project>

Ainsi pour une application Console générée avec:

dotnet new console -o <nom du projet>

L’entête du .csproj sera:

<Project Sdk="Microsoft.NET.Sdk">
  ...
</Project>

Et les déclarations des namespaces seront:

global using global::System
global using global::System.Collections.Generic
global using global::System.IO
global using global::System.Linq
global using global::System.Net.Http
global using global::System.Threading
global using global::System.Threading.Tasks 

Pour une application Web générée avec:

dotnet new web -o <nom du projet>

L’entête du .csproj sera:

<Project Sdk="Microsoft.NET.SdkWeb”>
  ...
</Project>

En plus des déclarations précédentes, les namespaces implicites seront:

global using global::System.Net.Http.Json
global using global::Microsoft.AspNetCore.Builder
global using global::Microsoft.AspNetCore.Hosting
global using global::Microsoft.AspNetCore.Http
global using global::Microsoft.AspNetCore.Routing
global using global::Microsoft.Extensions.Configuration
global using global::Microsoft.Extensions.DependencyInjection
global using global::Microsoft.Extensions.Hosting
global using global::Microsoft.Extensions.Logging 

On peut trouver une liste plus exhaustive des namespaces implicites sur learn.microsoft.com/en-us/dotnet/core/project-sdk/overview#implicit-using-directives.

Valeur par défaut

Pour tous les nouveaux projets ciblant .NET 6 et supérieur, la propriété ImplicitUsings est présente dans le .csproj avec la valeur enable:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <!-- ... -->
    <ImplicitUsings>enable</ImplicitUsings>
    <!-- ... -->
  </PropertyGroup>
</Project>

Si la propriété ImplicitUsings n’est pas présente dans le fichier .csproj, la fonctionnalité est désactivée par défaut.

Désactiver ImplicitUsings

Pour désactiver ImplicitUsings, on peut soit supprimer la propriété du fichier .csproj (la valeur par défaut est désactivée), soit explicitement la désactiver avec la valeur disable:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <!-- ... -->
    <ImplicitUsings>disable</ImplicitUsings>
    <!-- ... -->
  </PropertyGroup>
</Project>

Ajouter ou supprimer une déclaration using globale dans le .csproj

Il est possible d’ajouter ou de supprimer une déclaration using globale directement dans le fichier .csproj.
Pour effectuer une déclaration using globale dans le .csproj pour supprimer un namespace particulier, on peut utiliser la syntaxe:

<Project Sdk="Microsoft.NET.Sdk.Web">
  </PropertyGroup>
    <!-- ... -->
    <ItemGroup>
      <Using Remove="System.Threading.Tasks" />
    </ItemGroup>
</Project>

Par opposition, pour effectuer une déclaration globale permettant de rajouter un namespace particulier:

<Project Sdk="Microsoft.NET.Sdk.Web">
  </PropertyGroup>
    <!-- ... -->
    <ItemGroup>
      <Using Include="System.Net.Http" />
    </ItemGroup>
</Project>

Leave a Reply