Transfert de type dans le Common Language Runtime

Le transfert de type vous permet de déplacer un type vers un autre assembly sans avoir à recompiler les applications utilisant l’assembly d’origine.

Par exemple, supposons qu’une application utilise la classe Example dans un assembly appelé Utility.dll. Les développeurs de Utility.dll peuvent décider de refactoriser l’assembly, et dans le cadre du processus sont susceptibles de déplacer la classe Example vers un autre assembly. Si l’ancienne version de Utility.dll est remplacée par la nouvelle version de Utility.dll et son assembly auxiliaire, l’application utilisant la classe Example est mise en échec car elle ne peut pas localiser la classe Example dans la nouvelle version de Utility.dll.

Les développeurs de Utility.dll peuvent éviter ce problème en transférant les demandes pour la classe Example à l’aide de l’attribut TypeForwardedToAttribute. Si l’attribut a été appliqué à la nouvelle version de Utility.dll, les demandes associées à la classe Example sont transmises à l’assembly qui contient la classe. L’application existante continue à fonctionner normalement, sans nouvelle compilation.

Transférer un type

Le transfert de type se décompose en quatre étapes :

  1. Déplacez le code source associé au type de l’assembly d’origine à l’assembly de destination.

  2. Dans l’assembly où se trouvait le type, ajoutez un TypeForwardedToAttribute pour le type qui a été déplacé. Le code suivant représente l’attribut pour un type nommé Example qui a été déplacé.

     [assembly:TypeForwardedToAttribute(Example::typeid)]
    
     [assembly:TypeForwardedToAttribute(typeof(Example))]
    
  3. Compilez l’assembly qui contient désormais le type.

  4. Recompilez l’assembly dans lequel le type se trouvait, avec une référence à l’assembly qui contient désormais le type. Par exemple, si vous compilez un fichier C# de la ligne de commande, utilisez l’option Références (Options du compilateur C#) pour spécifier l’assembly contenant le type. Dans C++, utilisez la directive #using dans le fichier source pour spécifier l’assembly contenant le type.

Exemple de transfert de type C#

En reprenant l’exemple de description inventé ci-dessus, imaginez que vous développez Utility.dll et que vous disposez d’une classe Example. Utility.csproj est une bibliothèque de classes de base :

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

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsing>true</ImplicitUsing>
  </PropertyGroup>

</Project>

La classe Example fournit quelques propriétés et écrase Object.ToString :

using System;

namespace Common.Objects;

public class Example
{
    public string Message { get; init; } = "Hi friends!";

    public Guid Id { get; init; } = Guid.NewGuid();

    public DateOnly Date { get; init; } = DateOnly.FromDateTime(DateTime.Today);

    public sealed override string ToString() =>
        $"[{Id} - {Date}]: {Message}";
}

Imaginez maintenant qu’il existe un projet de consommation et qu’il est représenté dans l’assembly Contrôle serveur consommateur. Ce projet de consommation fait référence à l’assembly Utilitaire. Par exemple, il instancie l’objet Example et l’écrit dans la console dans son fichier Program.cs :

using System;
using Common.Objects;

Example example = new();

Console.WriteLine(example);

Lorsque l’application de consommation s’exécute, elle génère l’état de l’objet Example. À ce stade, il n’existe aucun transfert de type, car Consuming.csproj fait référence à Utility.csproj. Toutefois, le développeur de l’assembly Utilitaire décide de supprimer l’objet Example dans le cadre d’une refactorisation. Ce type est déplacé vers un Common.csproj nouvellement créé.

En supprimant ce type de l’assembly Utilitaire, les développeurs introduisent un changement cassant. Tous les projets de consommation s’interrompent lorsqu’ils sont mis à jour vers l’assembly Utilitaire le plus récent.

Au lieu d’exiger que les projets de consommation ajoutent une nouvelle référence à l’assembly Commun, vous pouvez transférer le type. Étant donné que ce type a été supprimé de l’assembly Utilitaire, il faudra que Utility.csproj référence Common.csproj :

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

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsing>true</ImplicitUsing>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\Common\Common.csproj" />
  </ItemGroup>

</Project>

Le projet C# précédent référence désormais l’assembly Communnouvellement créé. Il peut s’agir d’un PackageReference ou d’un ProjectReference. L’assembly Utilitaire doit fournir les informations de transfert de type. Par convention, les déclarations de transfert de type sont généralement encapsulées dans un seul fichier nommé TypeForwarders, examinez le fichier C# TypeForwarders.cs suivant dans l’assembly Utilitaire :

using System.Runtime.CompilerServices;
using Common.Objects;

[assembly:TypeForwardedTo(typeof(Example))]

L’assembly Utilitaire référence l’assembly Commun et transfère le type Example. Si vous souhaitez compiler l’assembly Utilitaire avec les déclarations de transfert de type et supprimer Utility.dll dans la classe Consommatrice, l’application consommatrice fonctionne sans être compilée.

Voir aussi