Reenvío de tipos en Common Language Runtime

El reenvío de tipos le permite mover un tipo a otro ensamblado sin tener que volver a compilar las aplicaciones que utilizan el ensamblado original.

Por ejemplo, suponga que una aplicación utiliza la clase Example en un ensamblado denominado Utility.dll. Los desarrolladores de Utility.dll podrían decidir refactorizar el ensamblado y, en el proceso, podrían mover la clase Example a otro ensamblado. Si la versión anterior de Utility.dll se reemplaza por la nueva versión de Utility.dll y por su ensamblado complementario, la aplicación que usa la clase Example produce un error porque no puede encontrar la clase Example en la nueva versión de Utility.dll.

Los desarrolladores de Utility.dll pueden evitarlo mediante el reenvío de solicitudes para la clase Example con el atributo TypeForwardedToAttribute. Si se ha aplicado el atributo a la nueva versión de Utility.dll, las solicitudes para la clase Example se reenvían al ensamblado que contiene la clase. La aplicación existente continuará funcionando normalmente, sin necesidad de volver a compilarla.

Reenvío de un tipo

Hay cuatro pasos para reenviar un tipo:

  1. Traslade el código fuente del tipo desde el ensamblado original al ensamblado de destino.

  2. En el ensamblado en el que solía estar ubicado el tipo, agregue un atributo TypeForwardedToAttribute para el tipo que se ha movido. El código siguiente muestra el atributo para un tipo denominado Example que se ha movido.

     [assembly:TypeForwardedToAttribute(Example::typeid)]
    
     [assembly:TypeForwardedToAttribute(typeof(Example))]
    
  3. Compile el ensamblado que contiene el tipo ahora.

  4. Vuelva a compilar el ensamblado donde se encontraba antes el tipo, con una referencia al ensamblado que contiene el tipo ahora. Por ejemplo, si va a compilar un archivo de C# desde la línea de comandos, utilice la opción Referencias (opciones de compilador de C#) para especificar el ensamblado que contiene el tipo. En C++, utilice la directiva #using en el archivo de código fuente para especificar el ensamblado que contiene el tipo.

Ejemplo de reenvío de tipos de C#

Siguiendo con la descripción del ejemplo ficticio anterior, imagine que está desarrollando el archivo Utility.dll y tiene una clase Example. Utility.csproj es una biblioteca de clases básica:

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

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

</Project>

La clase Example proporciona algunas propiedades e invalida 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}";
}

Ahora, imagine que hay un proyecto de consumo y se representa en el ensamblado Consumer. Este proyecto de consumo hace referencia al ensamblado Utility. Por ejemplo, crea una instancia del objeto Example y lo escribe en la consola en su archivo Program.cs:

using System;
using Common.Objects;

Example example = new();

Console.WriteLine(example);

Cuando se ejecute la aplicación de consumo, se generará el estado del objeto Example. En este momento, no hay reenvío de tipos, ya que Consuming.csproj hace referencia a Utility.csproj. Sin embargo, el desarrollador del ensamblado Utility decide quitar el objeto Example como parte de una refactorización. Este tipo se mueve a un archivo Common.csproj recién creado.

Al quitar este tipo del ensamblado Utility, los desarrolladores están introduciendo un cambio importante. Todos los proyectos de consumo se interrumpirán cuando se actualicen al ensamblado Utility más reciente.

En lugar de exigir que los proyectos de consumo agreguen una nueva referencia al ensamblado Common, puede reenviar el tipo. Puesto que este tipo se quitó del ensamblado Utility, deberá tener la referencia Utility.csproj a 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>

El proyecto de C# anterior ahora hace referencia al ensamblado Common recién creado. Puede ser PackageReference o ProjectReference. El ensamblado Utility debe proporcionar la información de reenvío de tipos. Por convención, las declaraciones de reenvío de tipos normalmente se encapsulan en un único archivo denominado TypeForwarders. Considere el siguiente archivo TypeForwarders.cs C# en el ensamblado Utility:

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

[assembly:TypeForwardedTo(typeof(Example))]

El ensamblado Utility hace referencia al ensamblado Common y reenvía el tipo Example. Si va a compilar el ensamblado Utility con las declaraciones de reenvío de tipos y va a colocar Utility.dll en el contenedor Consuming, la aplicación de consumo funcionará sin compilarse.

Vea también