Поделиться через


Переадресация типов в среде CLR (Common Language Runtime)

Переадресация типов позволяет перемещать тип в другую сборку без необходимости перекомпилировать приложения, использующие исходную сборку.

Например, предположим, что приложение использует Example класс в сборке с именем Utility.dll. Разработчики Utility.dll могут принять решение о рефакторинге сборки, и в процессе они могут переместить класс в Example другую сборку. Если старая версия Utility.dll заменена новой версией Utility.dll и ее компаньонной сборкой, приложение, использующее Example класс, завершается ошибкой, так как оно не может найти Example класс в новой версии Utility.dll.

Разработчики Utility.dll могут избежать этого, переадресовав запросы для Example класса с помощью атрибута TypeForwardedToAttribute . Если атрибут был применен к новой версии Utility.dll, запросы для Example класса перенаправляются в сборку, которая теперь содержит класс. Существующее приложение продолжает работать нормально, без повторной компиляции.

Переадресовать тип

Существует четыре шага переадресации типа:

  1. Переместите исходный код типа из исходной сборки в целевую сборку.

  2. В сборке, где раньше находился тип, добавьте TypeForwardedToAttribute для типа, который был перемещён. В следующем коде показан атрибут для типа с именем Example , который был перемещен.

     [assembly:TypeForwardedToAttribute(Example::typeid)]
    
     [assembly:TypeForwardedToAttribute(typeof(Example))]
    
  3. Скомпилируйте сборку, содержащую тип.

  4. Повторно компилируйте сборку, в которой находится тип, с ссылкой на сборку, которая теперь содержит тип. Например, если вы компилируете файл C# из командной строки, используйте параметр "Ссылки " (параметры компилятора C#), чтобы указать сборку, содержащую тип. В C++используйте директиву #using в исходном файле, чтобы указать сборку, содержащую тип.

Пример пересылки типов C#

Продолжая из приведенного выше описания примера, представьте, что вы разрабатываете Utility.dll, а также у вас есть класс Example. Utility.csproj — это базовая библиотека классов:

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

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

</Project>

Класс Example предоставляет несколько свойств и переопределяет 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}";
}

Теперь представьте, что есть проект-потребитель, и он представлен в сборке Consumer. Этот используемый проект ссылается на сборку Utility. Например, он создает экземпляр Example объекта и записывает его в консоль в файле Program.cs :

using System;
using Common.Objects;

Example example = new();

Console.WriteLine(example);

При запуске потребляющего приложения будет выведено состояние объекта Example. На этом этапе переадресация типов отсутствует, так как файл Consuming.csproj ссылается на Utility.csproj. Однако разработчики сборки служебной программы решили удалить Example объект в рамках процесса рефакторинга. Этот тип перемещается в только что созданный Common.csproj.

Удаляя этот тип из Utility сборки, разработчики внедряют значительное изменение. Все проекты, использующие сборку Utility, выйдут из строя при обновлении до последней версии.

Вместо того, чтобы требовать от потребляющих проектов добавлять новую ссылку на сборку Common, вы можете перенаправлять тип. Так как этот тип был удален из сборки Utility, вам потребуется, чтобы Utility.csproj ссылался на Common.csproj:

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

Предыдущий проект C# теперь ссылается на только что созданную общую сборку. Это может быть либо PackageReference, либо ProjectReference. Сборка утилиты должна предоставить сведения о переадресации типов. По соглашению, перенаправления типов обычно инкапсулируются в одном файле с именем TypeForwarders, рассмотрим следующий файл C# TypeForwarders.cs в сборке Utility:

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

[assembly:TypeForwardedTo(typeof(Example))]

Служебная сборка ссылается на общую сборку и перенаправит Example тип. Если вы собираетесь скомпилировать сборку Utility с объявлениями перенаправления типов и поместить Utility.dll в каталог Consuming, приложение потребления будет работать без компиляции.

См. также