Tuesday, July 24, 2007

Type forwarding in .NET 2.0 - TypeForwardedToAttribute

Type forwarding is a feature added in .NET 2.0. But I guess it was not publicized as much as Generics or any other new feature that was added. TypeForwardedToAttribute is about forwarding calls to methods in a type from one assembly to another assembly. Here goes its story.

Assume that you are developing a library, mylib.dll,  with some helper functions. And one of the types in that library is named FindText. FindText is a class with two member functions. Apart from FindText there are so many other classes and structures in that class. And an application named AppProjectA that consumes this dll.

But while implementing mylidb.dll you found that FindText is  becoming too complex with lot of Internationalization code and other stuff. So you thought of you can moving whole of FindText to a new library called strsearchlib.dll.

As application AppProjectA  is already distributed you are hesitant to recompile it. But you want to consume strsearchlib.dll for FindText instead of mylib.dll.

This is possible using TypeForwardedToAttribute in .NET 2.0.

Here goes Step by Step Guide.

1) Build mylib.dll

[Source] mylib.cs

namespace ProjectA
{
    public class FindText
    {
        public bool Find(string inputstr)
        {
            System.Console.WriteLine("In mylib");           
            return (inputstr=="text1");
        }
        public string Add(string inputstr)
        {
            System.Console.WriteLine("In mylib");           
            return (inputstr+=" end of line");
        }
    }
}

Launch VS2005 Command Prompt and build mylib.dll

$csc /t:library strsearchlib.cs

2) Build AppProjectA.exe

[Source] AppProjectA .cs:

using System;

namespace ProjectA
{
    public class App
    {
        static void Main()
        {
            string str1 = Console.ReadLine();
            FindText ft = new FindText();
            if (ft.Find(str1))
                Console.WriteLine("Found");
            else
                Console.WriteLine("Not Found");


            Console.WriteLine(ft.Add(str1));
        }
    }
}

$csc /r:mylib.dll AppProjectA.cs

3) Test AppProjectA.exe

Enter text "text1" and observe result Found.

4) Now build strsearchlib.dll 

Copy code for FindText from mylib.cs to strsearchlib.cs. Dont change anything, just copy.

[Source] strsearchlib.cs:

namespace ProjectA
{
    public class FindText
    {
        public bool Find(string inputstr)
        {
            System.Console.WriteLine("In strsearchlib");
            return (inputstr=="Search");
        }
        public string Add(string inputstr)
        {
            System.Console.WriteLine("In mylib");           
            return (inputstr+=" end of line");
        }
    }
}

$csc /t:library strsearchlib.cs

5) Rebuild mylib.dll

Add TypeForwardedToAttribute in mylib.cs and remove type FindText. You must comment/remove it.

[Source] mylib.cs:

[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(ProjectA.FindText))]
namespace ProjectA
{
/*    public class FindText
    {
        public bool Find(string inputstr)
        {
            System.Console.WriteLine("In mylib");           
            return (inputstr=="text1");
        }
        public string Add(string inputstr)
        {
            System.Console.WriteLine("In mylib");           
            return (inputstr+=" end of line");
        }
    }
*/

/*

Some other types

*/
}

$csc /r:strsearchlib.dll /t:library mylib.cs

6) Test AppProjectA.exe again and observe that calls to Find and Add methods are redirected to strsearchlib.dll

7) Observe change in manifest of mylib.dll

$ildasm mylib.dll

open manifest and observe forwarder

.class extern forwarder ProjectA.FindText
{
  .assembly extern strsearchlib
}

8) Metadata and IL Assembly syntax for Type forwarding in .NET 2.0

Metadata presentation of type forwarders
    ExportedType table
        Flags        | tdForwarder (0x00200000)
        TypeDefId
        TypeName
        TypeNamespace
        Implementation    = mdAssemblyRef

IL Assembler syntax
    .class extern public forwarder ProjectA.FindText
    {
        .assembly extern strsearchlib
    }

No comments: