# Tuesday, October 04, 2005
« The Wonders of Whidbey Factoring Feature... | Main | Going to VS Launch in Toronto and Ottawa... »

It’s high time for the next installment in this series. I was planning on getting to it sooner, but I’ve had a bunch of crazy things going on to do with getting the .NET Framework integrated into Windows Vista and planning for the next couple versions of the .NET Framework. None of that is calming down, but it’s time to get out another installment none the less.

 

I took a quick and somewhat vague look at type forwarders in my previous post (on purpose). Some of you were likely satisfied by that level of information and others are likely interested in more detail. As the title of this post suggests, this is the place to get more detail. To best do this, I’ve created a simple – and not particularly useful – application to demonstrate how forwarders really work. I’ll include this app in my next post.

 

Here is the entire program (it is only the Main method):

 

using System;

using StringUtilities;

using MathUtilities;

 

namespace TypeForwarderApp

{

    class Program

    {

        static void Main(string[] args)

        {

            Int32 int1, int2, intSum, stringCharacterCount;

            String initialString, reversedString;

            String appMessage;

 

            appMessage = "This app doesn't really do anything useful";

            Console.WriteLine(appMessage);

 

            int1 = 16;

            int2 = 14;

 

            initialString = "Happy 30th Birthday Microsoft!";

 

            intSum = MathUtil.Add(int1, int2);

 

            reversedString = StringReverse.GetReversedString(initialString);

            stringCharacterCount = StringCharacterCount.GetCount(initialString);

 

            Console.WriteLine();

            Console.WriteLine("Initial String : {0}", initialString);

            Console.WriteLine("Reversed String: {0}", reversedString);

            Console.WriteLine("String Length  : {0}", stringCharacterCount);

            Console.WriteLine();

            Console.WriteLine("Integers: {0}, {1}", int1, int2);

            Console.WriteLine("Sum     : {0}", intSum);

            Console.WriteLine();

            Console.WriteLine(StringReverse.GetReversedString(appMessage));

 

 

        }

    }

}

 

Like, I said, the program doesn’t do anything useful. I included the birthday message given that two Fridays ago was the annual Microsoft company meeting at SafeCo Field in Seattle. The theme was “Beyond 30” celebrating the first 30 years of Microsoft, although the content was much more about the future than the past (which I imagine most folks there appreciated). The 25th anniversary meeting was much more of a history lesson. I think that was the one that Sinbad was at ;)

 

I’m going to concentrate on one type, the StringCharacterCount type. At the moment, it is part of the StringUtilties assembly. If we look at the MSIL code within TypeForwarderApp.exe, we’ll see that clearly.

 

This is the MSIL code within the exe that calls the static method GetString on the StringCharacterCount type:

 

  IL_0030:  call       int32 [StringUtilities]StringUtilities.StringCharacterCount::GetCount(string)

 

As you can see, the fact that StringCharacterCount lives within the StringUtilities assembly is pretty apparent. Actually, you could go as far as saying it is hard-coded. Hence the need for forwarders …

 

Well, I’m a typical developer and I’ve decided in my second version of StringUtilites and MathUtilites – I happen to own them both – that StringCharacterCount is really a math utility and less of a string utility. As a result, I’m going to move this cool type to the MathUtilities assembly.

 

I just moved it to the MathUtilties assembly. You can see that it is indeed part of the MathUtilities assembly via the MetaInfo (CTRL-M) view in ILDasm.

 

TypeDef #2 (02000003)

-------------------------------------------------------

      TypDefName: StringUtilities.StringCharacterCount  (02000003)

      Flags     : [Public] [AutoLayout] [Class] [AnsiClass] [BeforeFieldInit]  (00100001)

      Extends   : 01000001 [TypeRef] System.Object

      Method #1 (06000003)

      -------------------------------------------------------

            MethodName: GetCount (06000003)

 

Notice that the StringCharacterCount type is still part of the StringUtilities namespace and not MathUtilties. This is for two reasons: the namespace is part of the type name and type forwarders do not change the type name in any way. Put another way, if I moved StringCharacterCount from the one assembly to the other *and* changed its namespace, then I would have a breaking change that even type forwarders could not mitigate.

 

This all makes sense, but we have yet to see the interesting part. What does the metadata within the new version of StringUtilties look like? Let’s take a look at the manifest (another ILDasm view) within the StringUtilties assembly. There are actually two additional directives that we didn’t have before.

 

.assembly extern MathUtilities

{

  .ver 1:0:0:0

}

.class extern forwarder StringUtilities.StringCharacterCount

{

  .assembly extern MathUtilities

}

 

StringUtilties now has a dependency on MathUtilties and there is this “.class extern forwarder” line for “StringUtilities.StringCharacterCount”. Clearly, we’ve hit our jackpot. The dependency on MathUtilities is clearly required, given that StringUtilities intends to forward to it. The second directive, the class directive, is a way to signal to the runtime that the assembly knows about the class, but that it is located at another location.

 

If we look further yet, we’ll see that there is an entry in ExportedType table.

 

ExportedType #1 (27000001)

-------------------------------------------------------

      Token: 0x27000001

      Name: StringUtilities.StringCharacterCount

      Implementation token: 0x23000002

      TypeDef token: 0x00000000

      Flags     : [NotPublic] [AutoLayout] [Class] [AnsiClass] [Forwarder]  (00200000)

 

We’re now looking at metadata instead of the MSIL view (the directives) above. The ExportedType table is generally used to publish all the types in child netmodules of an assembly – build a multi-module assembly and you’ll notice this first-hand. In the case of multi-module assemblies, the implementation token would point to the netmodule, not to a separate assembly. In the case of type forwarders, the implementation token points (naturally) to a separate assembly. We can easily prove that too. Look at the AssemblyRef entry for the MathUtilities Assembly below.

 

AssemblyRef #2 (23000002)

-------------------------------------------------------

      Token: 0x23000002

      Public Key or Token:

      Name: MathUtilities

      Version: 1.0.0.0

      Major Version: 0x00000001

      Minor Version: 0x00000000

      Build Number: 0x00000000

      Revision Number: 0x00000000

      Locale: <null>

      HashValue Blob:

      Flags: [none] (00000000)

 

Notice that its token (0x23000002)  matches the implementation token of our forwarded type (0x23000002). There you go. That’s it! Now you know everything I’m going to tell you about type forwarders.