Type forwarding allows you to move a type to another assembly without having to recompile applications that use the original assembly.
For example, suppose an application uses the Example class in an assembly named Utility.dll. The developers of Utility.dll might decide to refactor the assembly, and in the process they might move the Example class to another assembly. If the old version of Utility.dll is replaced by the new version of Utility.dll and its companion assembly, the application that uses the Example class fails because it cannot locate the Example class in the new version of Utility.dll.
The developers of Utility.dll can avoid this by forwarding requests for the Example class, using the TypeForwardedToAttribute attribute. If the attribute has been applied to the new version of Utility.dll, requests for the Example class are forwarded to the assembly that now contains the class. The existing application continues to function normally, without recompilation.
Forward a type
There are four steps to forwarding a type:
Move the source code for the type from the original assembly to the destination assembly.
In the assembly where the type used to be located, add a TypeForwardedToAttribute for the type that was moved. The following code shows the attribute for a type named Example that was moved.
Recompile the assembly where the type used to be located, with a reference to the assembly that now contains the type. For example, if you are compiling a C# file from the command line, use the References (C# compiler options) option to specify the assembly that contains the type. In C++, use the #using directive in the source file to specify the assembly that contains the type.
C# type forwarding example
Continuing from the contrived example description above, imagine you're developing the Utility.dll, and you have an Example class. The Utility.csproj is a basic class library:
The Example class provides a few properties and overrides Object.ToString:
C#
using System;
namespaceCommon.Objects;
publicclassExample
{
publicstring Message { get; init; } = "Hi friends!";
public Guid Id { get; init; } = Guid.NewGuid();
public DateOnly Date { get; init; } = DateOnly.FromDateTime(DateTime.Today);
publicsealedoverridestringToString() =>
$"[{Id} - {Date}]: {Message}";
}
Now, imagine that there is a consuming project and it's represented in the Consumer assembly. This consuming project references the Utility assembly. As an example, it instantiates the Example object and writes it to the console in its Program.cs file:
C#
using System;
using Common.Objects;
Example example = new();
Console.WriteLine(example);
When the consuming app runs, it will output the state of the Example object. At this point, there is no type forwarding as the Consuming.csproj references the Utility.csproj. However, the developer's of the Utility assembly decide to remove the Example object as part of a refactoring. This type is moved to a newly created Common.csproj.
By removing this type from the Utility assembly, the developers are introducing a breaking change. All consuming projects will break when they update to the latest Utility assembly.
Instead of requiring the consuming projects to add a new reference to the Common assembly, you can forward the type. Since this type was removed from the Utility assembly, you'll need to have the Utility.csproj reference the Common.csproj:
The preceding C# project now references the newly created Common assembly. This could be either a PackageReference or a ProjectReference. The Utility assembly needs to provide the type forwarding information. By convention type forward declarations are usually encapsulated in a single file named TypeForwarders, consider the following TypeForwarders.cs C# file in the Utility assembly:
C#
using System.Runtime.CompilerServices;
using Common.Objects;
[assembly:TypeForwardedTo(typeof(Example))]
The Utility assembly references the Common assembly, and it forwards the Example type. If you're to compile the Utility assembly with the type forwarding declarations and drop the Utility.dll into the Consuming bin, the consuming app will work without being compiled.
Izvor za ovaj sadržaj možete pronaći na GitHubu, gdje možete stvarati i pregledavati probleme i zahtjeve za povlačenjem. Dodatne informacije potražite u našem vodiču za suradnike.
Povratne informacije o proizvodu .NET
.NET je projekt otvorenog koda. Odaberite vezu za slanje povratnih informacija:
Pridružite se seriji susreta kako biste s kolegama programerima i stručnjacima izgradili skalabilna rješenja umjetne inteligencije temeljena na stvarnim slučajevima upotrebe.
For valid input to reflection operations, use fully qualified type names, which have assembly name specifications, namespace specifications, and type names.
Learn about the .NET 7 breaking change in core .NET libraries where resolving a collectible Assembly in a non-collectible AssemblyLoadContext results in a FileLoadException.
Emit dynamic methods and assemblies using the System.Reflection.Emit namespace, which allows a compiler or tool to emit metadata and CIL code at run time.
This feature specification describes how to declare module initializers, which are methods called by the runtime when a module, or assembly, is loaded.