Saturday, October 07, 2006 1:26 AM bart

Using aliases in C# - Notes on extern alias, the :: operator and even more

Introduction

Today I have a post for you about a feature that's not so well-known as it should be in my opinion: aliases in C#. Everyone should know about the using keyword to import a namespace:

using System;

...

Console.WriteLine("Hello"); //instead of System.Console.WriteLine

It doesn't have any runtime implications whatsoever (some small amount of people think that having more namespace imports implies performance dropdown :o), it's just used at compile-time to locate classes. Recall that the CLR doesn't know about namespaces, it just identifies classes by their full name (e.g. System.Collections.Stack).

Basics of namespace imports

But what about having a class with the same (language-level without namespace qualifier) name in multiple namespaces?

namespace Sample.First
{
   public class
Bar { }
}

namespace
Sample.Second
{
   public class
Bar { }
}

namespace
Demo
{
   using
Sample.First;
   using
Sample.Second;

   class
Program
   {
      public static void
Main()
      {
         Bar b =
new
Bar();
      }
   }
}

Right, the compiler complains: error CS0104: 'Bar' is an ambiguous reference between 'Sample.First.Bar' and 'Sample.Second.Bar'.

So you have to disambiguate by using a full qualified namespace/class notation. Alternatively you can define aliases:

namespace Demo
{
   using
A = Sample.First;
   using
B = Sample.Second;

   class
Program
   {
      public static void
Main()
      {
         A.Bar b =
new
A.Bar();
      }
   }
}

This is a commonly applied technique to abbreviate namespaces, for example in VSTO:

using Outlook = Microsoft.Office.Interop.Outlook;
using Word = Microsoft.Office.Interop.Word;

Aliases for class names

However, it's a common misbelief that this kind of aliasing only works with namespaces. You can use it to create an alias for a class as well, as shown below:

using System;
using System.Collections.Generic;
using IntList = System.Collections.Generic.List<int
>;
using List = System.Collections.ArrayList
;

class
Program
{
   public static void
Main()
   {
      IntList lst = new IntList
();
      Console
.WriteLine(lst.GetType());

      List
lstc = new List();
      Console
.WriteLine(lstc.GetType());

      List<int> lstg = new List<int>();
      Console.WriteLine(lstg.GetType());
   }
}

I chose this example to show the possible confusion that can be introduced by this: List is defined as a non-generic ArrayList in this case. However, when using a type parameter it's treated as a generic list variant in System.Collections.Generic. The IntList alias should be pretty clear. Here's the app's output:

System.Collections.Generic.List`1[System.Int32]
System.Collections.ArrayList
System.Collections.Generic.List`1[System.Int32]

Kind of a very lightweight #define equivalent if you want. The only allowed aliases are textual names without dots in it (things like Bar.Foo or Foo<T> won't work).

Extern aliases

Yet another feature are extern aliases. See Robert's comment about the VS2005 IDE support for this (thanks to Robert for pointing this out!). As command-line geeks, we'll stick at the bottom of the stack, enjoying csc.exe fun. Absorb the following scenario:

Library 1 (lib1.dll)

namespace Bar
{
   public class
Abc { }
   public class
Foo { }
}

Library 2 (lib2.dll)

namespace Bar
{
   public class
Def { }
   public class
Foo { }
}

Is this valid to do? Yes of course, since we define a class (coincidentally or not) with the same name "Bar.Foo" in two different assemblies there is no conflict. If you'd compile it into one library the CS0101 error would pop up (telling you have two identical definitions). However, when you start both libraries in one single application, problems appear:

using Bar;

class
Program
{
   public static void
Main()
   {
      Foo f =
new
Foo();
   }
}

Using the following command-line compiler invocation:

csc /r:lib1.dll,lib2.dll program.cs

Which Foo should be used? The compiler can't know your intentions. Now assume you haven't created this ugly situation yourself and you find two libraries which contain a class with the same name and you want to use both classes at the same time in the same project (a typical example of Murhpy's Law). The compiler will complain as follows:

error CS0433: The type 'Bar.Foo' exists in both 'c:\temp\lib1.dll' and 'c:\temp\lib2.dll'

There is however a solution to this: extern aliases. Change the program's code as follows:

extern alias Lib1;
extern alias Lib2;


class Program
{
   public static void Main()
   {
      Lib1::Bar.Foo f1 =
new Lib1::Bar.Foo();
      Lib2::Bar.Foo f2 = new Lib2::Bar.Foo();
   }
}

or

extern alias Lib1;
extern alias Lib2;

using Lib1::Bar;

class Program
{
   public static void
Main()
   {
      Foo f1 =
new
Foo();
      Lib2::Bar.Foo f2 = new Lib2::Bar.Foo();
   }
}

or

extern alias Lib1;
extern alias Lib2;

using Bar1 = Lib1::Bar;
using Bar2 = Lib1::Bar;

class
Program
{
   public static void
Main()
   {
      Bar1.Foo f1 =
new
Bar1.Foo();
      Bar2.Foo f2 = new Bar2.Foo();
   }
}

Compilation should be performed like this:

csc /r:Lib1=lib1.dll /r:Lib2=lib2.dll program.cs

Things learned:

Finally there's also the concept of the "global namespace". For example you can refer to System.Diagnostics.Process from the BCL using the global::System.Diagnostics.Process syntax. This is also a good IntelliSense trick to find out about top-level namespaces that are available:

Have fun!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under:

Comments

# re: Using aliases in C# - Notes on extern alias, the :: operator and even more

Saturday, October 07, 2006 4:28 AM by Robert W. Anderson

Great post.  The part about disambiguating across libraries actually helped me deal with an issue I had today.

You did get one thing wrong, though: the VS2005 UI does support library aliases directly without getting into MSBuild.  It can be set under the propeties pane for the referenced library under "Aliases".

# re: Using aliases in C# - Notes on extern alias, the :: operator and even more

Saturday, October 07, 2006 2:14 PM by bart

Hi Robert,

Thanks for pointing this out. I guess it's the price to pay when you live close to the bottom of the stack instead of relying on tools on a day to day basis :-). Call me a command-line and csc freak if you will... No seriously, I'm often impressed about the tools in a positive way when I discover this kind of little things that make life easier, so thx a lot.

-Bart

# re: Using aliases in C# - Notes on extern alias, the :: operator and even more

Saturday, October 07, 2006 4:58 PM by Robert W. Anderson

Glad to help . . . I move up and down the stack fairly often depending on what I'm doing and what it is for.  I personally get pretty annoyed when the VS doesn't directly support use cases like this one.  My personal (un)favorite: no way to add Win32 resources to managed assemblies through VS.

Cheers,
Robert

# .Sitecore &raquo; Good news about Web Application model and namespaces