类型转发允许将类型移动到另一个程序集,而无需重新编译使用原始程序集的应用程序。
例如,假设应用程序在名为 Example
的程序集中使用类。 Utility.dll 的开发人员可能会决定重构程序集,在此过程中,他们可能会将Example
类移动到另一个程序集。 如果旧版本的 Utility.dll 替换为新版本 的Utility.dll 及其配套程序集,则使用该 Example
类的应用程序将失败,因为它无法在 Example
新版本 的Utility.dll中找到该类。
Utility.dll 的开发人员可以通过使用Example
特性转发类TypeForwardedToAttribute的请求来避免这种情况。 如果已向新版本的 Utility.dll 应用了该属性,则对 类的请求会转发到该类目前所属的程序集Example
。 现有应用程序继续正常运行,无需重新编译。
转发类型
转发某类型需要经过四个步骤:
将类型源代码从原始程序集移动到目标程序集。
在类型曾存于的程序集中,为已移动的类型添加 TypeForwardedToAttribute。 以下代码显示了已移动的类型
Example
的属性。[assembly:TypeForwardedToAttribute(Example::typeid)]
[assembly:TypeForwardedToAttribute(typeof(Example))]
编译该类型目前所属的程序集。
重新编译原本包含该类型的程序集,并引用现在包含该类型的程序集。 例如,如果要从命令行编译 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 程序集中表示。 此消耗项目引用 实用工具 程序集。 例如,它会实例化Example
对象并将其写入控制台Program.cs文件中:
using System;
using Common.Objects;
Example example = new();
Console.WriteLine(example);
当消费应用程序运行时,它将输出Example
对象的状态。 此时,没有类型转发,因为 Consuming.csproj 引用 Utility.csproj。 但是, 实用工具 程序集的开发人员决定将对象作为重构的一部分删除 Example
。 此类型将移动到新创建的 Common.csproj。
开发人员通过从 实用工具 程序集中删除此类型,从而引入重大改变。 所有依赖该程序集的项目在更新到最新的 实用程序集 时都会中断。
可以转发类型,而不是要求使用项目添加对 Common 程序集的新引用。 由于此类型已从实用工具程序集中删除,因此需要让 Utility.csproj 引用 Common.csproj:
<ItemGroup>
<ProjectReference Include="..\Common\Common.csproj" />
</ItemGroup>
前面的 C# 项目现在引用新创建的 通用 程序集。 这可以是 PackageReference
或 ProjectReference
。 Utility程序集需要提供类型转发信息。 按照惯例,类型前向声明通常封装在一个名为 TypeForwarders
的文件中,请考虑 Utility 程序集中的以下 TypeForwarders.cs C# 文件:
using System.Runtime.CompilerServices;
using Common.Objects;
[assembly:TypeForwardedTo(typeof(Example))]
实用工具程序集引用 Common 程序集,并转发类型Example
。 如果将Utility程序集与类型转发声明一起编译,并将Utility.dll放置到Consuming bin中,使用的应用程序将可以运行而无需编译。