.NET has a very interesting new feature regarding type identity. When I tested this feature the last time (I think it was with the RC, it did not work, so it is likely you have not yet heared about it). But let's start from the beginning:
Type identity is a very important concept of a programming infrastructure. In classic C++, types are identified by their names. COM uses GUIDs to identitfy types. To achieve a strong type safety, type identity in .NET is bound to assembly identity and assembly identity can be bound to developers using a public/private key pair. Type identity is bound to assembly identity means that 2 types with the same name in two different assemblies have two different identities. Assembly identity can be bound to developers using a public/private key pair means that developers can use unique public/private key pairs to give their assemblies unique and uncloneable names. This also gives all types in the assembly unique and uncloneable names.
The following expression returns a string containing the unique and uncloneable type identity, Microsoft has given to the 32 bit signed integer type:
int::typeid->AssemblyQualifiedName
If you are not familiar with the chosen language, the equivalent C# expression would be typeof(int).AssemblyQualifiedName.
While this type identity is very helpful to achieve verifiability, it is also had a drawback: This assembly bound type identity ment that a type could not leave the assembly where it was defined in without losing it's identity. You can define a type from exactly the same code in another assembly, but to the runtime, it would be a different type. To understand this, let's have a look at the following example.
Let's assume you have an assembly lib1.dll created from the following code:
public ref class TheType {};
Let's further assume, you have a client application like this one:
#using "lib1.dll"
int main() {
using namespace System;
Console::WriteLine(TheType().GetType()->AssemblyQualifiedName);
using System::Reflection::Assembly;
for each (Assembly^ a in AppDomain::CurrentDomain->GetAssemblies())
Console::WriteLine(a->FullName);
}
Notice the elegant way to add an assembly reference inside your code, and the neat alternative for creating a temporary object of type TheType - two out of so many reasons why I call C++/CLI the chosen language.
If you run the application, you will see that TheType is defined in Lib1 and that the assemblies mscorlib, app, and lib1 are loaded.
Let's further assume that for the next version, you are redesigning your application and you find out, that TheType would now better fit into another assembly. Due to the type identity rules I have mentioned, this would mean that TheType would get another identity. Therefore this would be a breaking change for lib1.dll: The new version of Lib1 would not be backwards compatible with the old one, since it didn't have the public type TheType any more.
Using the type identity mapping feature in 2.0, you can reorganize your libraries without causing a backwards incompatibility in your new lib1.dll. To explain the mechanics, let's assume the source for lib2.dll now contains TheType:
//lib2.cs
public ref class TheType {};
To allow the old version of app.exe to execute even though TheType is no longer in the assembly where it is expected (lib1), you can define TheType in lib1.dll with a type identity mapping to the type in lib2.dll. These two lines are enough to achieve this:
#using "lib2.dll"
[assembly: TypeForwardedTo(TheType::typeid)];
Notice that this code creates lib1.dll with an assembly depencency to lib2.dll that defines TheType. When using this code, the compiler emits the folowing metadata for TheType in lib1.dll:
.class extern forwarder TheType
{
.assembly extern lib2
.class 0x02000002
}
.class 0x02000002 is to the metadata token for TheType in lib2.dll.
Almost the same metadata can be emitted by C#, too; however there is a slight difference:
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(TheType))]
C# expects you to use the pseudo custom attribute System::Runtime::CompilerServices::TypeForwardedToAttribute, whereas C++/CLI uses a compiler-internal attriubte TypeForwardedTo. The philosophies of the two languages differ here: C# tries to be consistent in the way attributes are used. Regarding attributes, C++/CLI has different roots anyway: .NET attributes are, attributed ATL are two examples. Instead of trying to be consistent with one or the other attribute model, C++/CLI tries to avoid that the programmer has to explicitly use features of the runtime that are intended to be used by compiler builders only.
Whatever language you use, this simple attribute allows you to reorganize your libraries without breaking compatibility with old applications.