Archive for the ‘TypeForwardedTo’ tag
.NET Type Forwarding – Moving Types Between Assemblies
I learned about this really cool feature in the .NET framework while reading an MS certification book, and could not stop blogging about it. Type forwarding in .NET allows you to move type from one assembly to another without recompiling applications that use the old assembly.
Important Notes:
- Microsoft Visual Basic 2005 does not support the use of the TypeForwardedToAttribute attribute to forward types written in Visual Basic 2005. Applications written in Visual Basic 2005 can use forwarded types written in other languages.
- The compilers do not support forwarding generic types in .NET 2.0, 3.0 and 3.5. Support for this was added in .NET 4.0.
For this example, I would write one assembly called Animal that would contain a class called Dog, which would be consumed by an application called Consumer1. Later, I would move the Dog class to a new assembly called Canine, and we would see how we can make the Consumer1 application still work using .NET type forwarding feature.
Animal (Class Library)
As discussed here is the Dog class that would reside inside the Animal assembly.
Dog.cs
namespace Animal
{
using System;
public class Dog
{
/// <summary>
/// Make the dog bark.
/// </summary>
public void Bark()
{
Console.WriteLine("Arrgh.... Woof Woof!");
}
}
}
It’s a very simple class that contains a public method called Bark, which would output "Arrgh…. Woof Woof!" to the console when invoked.
Consumer1 (Console Application)
I would now write our first application that would consume the animal assembly. Its a simple console application that has reference to the Animal assembly.
namespace Consumer1
{
using System;
using Animal;
/// <summary>
/// The program.
/// </summary>
internal class Program
{
#region Methods
/// <summary>
/// The entry point.
/// </summary>
/// <param name="args">
/// The command line arguments.
/// </param>
private static void Main(string[] args)
{
Console.WriteLine("Consumer 1 Application");
Dog dog = new Dog();
dog.Bark();
Console.ReadKey();
}
#endregion
}
}
In the main method of the Consumer1 application I have created an instance of the Dog class and then called its Bark method. When we run this application we would get the following output.
Output:
Consumer 1 Application
Arrgh…. Woof Woof!
Canine (Class Library)
I moved the Dog class from Animal assembly to the new assembly called Canine.
namespace Animal
{
using System;
public class Dog
{
/// <summary>
/// Make the dog bark.
/// </summary>
public void Bark()
{
Console.WriteLine("Arrgh.... Woof Woof! (Inside New Assembly)");
}
}
}
The only difference in the class definition here, is the text that I output to the console when the Bark method is invoked. I have changed it so that we can easily spot out that our old application (Consumer1) is accessing the Dog class from the new Canine assembly.
Also you might wonder, if the assembly name is Canine then why is the namespace for the Dog class still Animal? It’s necessary to keep the old namespaces while moving types between assemblies for the old applications to find the type in the new assembly.
If we deploy the Animal assembly without the Dog class then existing installed applications that were compiled against the old Animal assembly would break. Unless, we use type forwarding in the modified Animal assembly and let it know where to look for the Dog class when its requested. To enable type forwarding we need to do the following things:
- Add a reference of the new Canine assembly to the Animal assembly.
- Add the TypeForwardedToAttribute attribute to the animal assembly and specify the type to be forwarded.
Normally we add all assembly attributes to the AssemblyInfo.cs file. The TypeForwardedToAttribute attribute resides in the System.Runtime.CompilerServices namespace. Add the following line to the AssemblyInfo.cs.
using System.Runtime.CompilerServices; // Type forward the dog class to the Canine assembly [assembly: TypeForwardedTo(typeof(Animal.Dog))]
When any application would look for the Dog class in the Animal assembly it would be forwarded to the Canine assembly. Now when we deploy the new Animal & Canine assembly though the Consumer1 application does not have a reference to the Canine assembly, it would still find the Dog class and produce the following output.
Output:
Consumer 1 Application
Arrgh…. Woof Woof! (Inside New Assembly)
Deploying both the assemblies are important. Otherwise the Consumer1 application will not find the Dog class, and would crash.
Source Code:
