Suppose I have developed a wonderful library. It contains some base types and extended functionalities on top of the base types. I publish the library and people are happily using it. Life is wonderful.

Now I am up to develop the v2 version of the library.  I discovered that my implementation fo the extended functionality isn’t the best of the world and I have a way to improve it. As I move along, I realize that something isn’t right. I have applications using v1 of my library, and applications using v2 of my library. When the two kinds of applications want to exchange the base types I defined in my library,  it receives a InvalidTypeCast exception because now the base types now live in different assemblies!

I can force both applications to use v2 version of my library by using a publisher policy assembly. But my new implementation is likely to break existing applications that uses v1 of my library.

I guess I have to leave the library as it is forever, and add the new implementation to a new assembly. But it sucks that I have to keep the inferior implementation forever.

I so wish that I have shipped two assemblies originally. One only contains the base types, and the other one contains the extended functionalities. This way I can freely change base types between applications, while innovate in the functionality space.

Well, in .Net framework 2.0, you can use so called “Type forwarding” feature, to break the assembly in two pieces, and still maintain the backward compatibility.

In .Net framework 2.0, a custom attribute TypeForwardedTo is introduced to achieve this. In our example, you can move the implementation of the extended functionalities to a different assembly, and rebuild the original assembly with the extended functionalities forwarded to the new assembly. The re-built assembly contains the definition of extended functionalities but it does not contain the real implementation. At certain point in the future, when everyone has moved to the new implementaion, you can safely deprecate the old implementation.  

The following is an example of type forwarding in action:

AsmV1.dll has a type of Foo:

E:\TypeForwarding>more asmv1.cs

using System;
public class Foo
{
}


E:\TypeForwarding>csc /t:library asmv1.cs

Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.42
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.

We have an application using Foo in asmv1.

E:\TypeForwarding>more test.cs

using System;
public class Test
{
    public static void Main()
    {
        Foo foo = new Foo();
        Console.WriteLine(typeof(Foo).AssemblyQualifiedName);
    }
}

E:\TypeForwarding>csc /r:asmv1.dll test.cs

Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.42
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.

When we run test application it shows that it is using Foo in asmv1.

E:\TypeForwarding>test

Foo, asmv1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

Now let’s move class Foo to a new assembly asmv2

E:\TypeForwarding>more asmv2.cs

using System;
public class Foo
{
}

E:\TypeForwarding>csc /t:library asmv2.cs

Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.42
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.

And forward the implementation of Foo in asmv1 to asmv2.

E:\TypeForwarding>more asmv1.cs

using System;
using System.Runtime.CompilerServices;
[assembly:TypeForwardedTo(typeof(Foo))]

E:\code\TypeForwarding>csc /t:library /r:asmv2.dll /out:asmv1.dll asmv1.cs

Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.42
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.

Let’s run the test application again:

E:\TypeForwarding>test

Foo, asmv2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

The test application now is using class Foo from assembly asmv2.

The implementation of type forwarding has a few limitations in .Net framework v2.0:

1.      Type can not be renamed when forwarded. You can only forward a type to a type in a different assembly with the same name.

2.      Forwarded type cannot be referenced. In our example, if you try to re-build the test application with reference to asmv1.dll, you will receive an compiler error.

E:\code\TypeForwarding>csc /r:asmv1.dll test.cs

Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.42

for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727

Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.

 

test.cs(7,9): error CS0246: The type or namespace name 'Foo' could not be found

        (are you missing a using directive or an assembly reference?)

test.cs(7,23): error CS0246: The type or namespace name 'Foo' could not be found (are you missing a using directive or an assembly reference?)

test.cs(8,34): error CS0246: The type or namespace name 'Foo' could not be found (are you missing a using directive or an assembly reference?)

3.      Forwarded types are not shown in Assembly.GetTypes().

E:\code\TypeForwarding>more dumptype.cs

using System;

using System.Reflection;

 

public class DumpType

{

    public static void Main(String[] argv)

    {

        Assembly asm = Assembly.ReflectionOnlyLoadFrom(argv[0]);

        foreach(Type t in asm.GetTypes()) {

            Console.WriteLine(t.AssemblyQualifiedName);

        }

        Console.WriteLine("Done");

    }

}

 

E:\code\TypeForwarding>dumptype asmv2.dll

Foo, asmv2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null

Done

 

E:\code\TypeForwarding>dumptype.exe asmv1.dll

Done

All those limits may be lifted in the future .Net framework releases.

(In practice, it is very likely that you want to make the assembly, and the assembly being forwarded to friend assemblies.)

The C++ team is kindly provided a sample on how to use type forwarding in C++/CLI:

http://msdn2.microsoft.com/en-us/library/ms177220.aspx