Click here to Skip to main content
Click here to Skip to main content

C# 2.0 Aliases

, 3 Oct 2005
Rate this:
Please Sign up or sign in to vote.
A general description of C# 2.0 aliases.

Introduction

Undeniably, the discussion on aliases cannot be tackled without a quick history on their scope of use. Of course, to attack this subject, a brief lecture on namespaces is necessary so here it goes. C# namespaces allow you to create a system to organize your code in a hierarchical manner. An example of this is given below:

namespace Apresss
{
    namespace Data
    {
        public class DataManager
        {
        
        }
    }
    
    namespace IO
    {
        public class BluetoothReader
        {
        
        }
    }
}

The items within can either be accessed via the fully qualified type name, as illustrated in the example below:

Apress.Data.DataManager dman = new Apress.Data.DataManager();

Or, by explicitly scoping to items of that namespace with the using declaration. An example of this is given below:

using Apress.IO;
class Program
{
    static void Main(string[] args)
    {
        Apress.Data.DataManager dman = new Apress.Data.DataManager();
        BluetoothReader btooth = new BluetoothReader();
    }

}

The only purpose of the using command in this context is to save you typing and make your code simpler. It does not, for example, cause any other code or libraries to be added to your project. Besides providing us with the ability to permit types in a given namespace without qualification, the using keyword can also provide us the ability to create aliases for a namespace. An example of this is provided below:

using aio = Apress.IO;

and the ability to provide aliases for types as in the example below:

using Apress.IO;
using aio = System.Console;
class Program
{
    static void Main(string[] args)
    {
        aio.WriteLine("Aliased Type."); 
    }

}

In the above example, the type System.Console has been given a new name aio. The code inside the program’s Main method can now access members of Console through this alias.

The most common use of aliases is in situations where name collisions occur between two libraries, or when a small number of types from a much larger namespace are being used. Examine the sample listed below:

namespace Apress
{
    namespace Data
    {
        public class DataManager
        {
        
        }
    
        public class BluetoothReader
        {
        
        }
    }
    
    namespace IO
    {
        public class BluetoothReader
        {
        
        }
    }
}

The namespaces Apress.Data and Apress.IO have types with the same name. Applying the using directive to access type members in both namespaces and then trying to instantiate a BluetoothReader will create an ambiguity that cannot be resolved hence the code listed below will not compile:

using Apress.IO;
using Apress.Data;

class Program
{
    static void Main(string[] args)
    {
        BluetoothReader bt = new BluetoothReader(); 
    }

}

What’s new to aliases?

Aliasing namespaces appear to be an adequate solution in the example listed above. The sample illustrates once again how this works:

using apressio = Apress.IO;
using apresssdata = Apress.Data;

class Program
{
    static void Main(string[] args)
    {
        apressio.BluetoothReader bt = 
             new apressio.BluetoothReader(); 
    }

}

Unfortunately, there are situations where this practice would produce errors. The problem rears its ugly head when namespace names within the referenced libraries collide with our given alias names. The example below illustrates this problem:

namespace apressio
{
    public class TypeB
    {
    
    }
}

namespace apressdata
{
    public class TypeA
    {
    
    }
}

namespace Apress
{

    namespace Data
    {
        public class DataManager
        {
        
        }
        
        public class BluetoothReader
        {
        
        }
    }
    
    namespace IO
    {
        public class BluetoothReader
        {
        
        }
    }
}

In the example above, two new namespaces apressio and apressdata have been added, because they share common names with our aliases the code will not be allowed to compile. A quick solution to the problem is to move the alias definition out of module scope and into the namespace where they are used. The example below illustrates the initial problem:

using apressio = Apress.IO;
using apressdata = Apress.Data;


namespace apressio
{
    public class TypeB
    {
    
    }
}

namespace apressdata
{
    public class TypeA
    {
    
    }
}

namespace Apress
{

    namespace Data
    {
        public class DataManager
        {
        
        }
        
        public class BluetoothReader
        {
        
        }
    }
    
    namespace IO
    {
        public class BluetoothReader
        {
        
        }
    }
}


namespace Aliases
{

    class Program
    {
        static void Main(string[] args)
        {
        
            //apressio.Bluetooth
            apressio.BluetoothReader bt = 
               new apressio.BluetoothReader();
        }
    }
}

Here the aliases apressio and apressdata are defined in the typical location at the beginning of the C# file. Attempting to compile this code will fail. In order to get it to compile without introducing any new technology, simply move the declarations inside the namespace where they are used. The Aliases namespace is now defined as follows:

namespace Aliases
{
    using apressio = Apress.IO;
    using apressdata = Apress.Data;
    
    class Program
    {
        static void Main(string[] args)
        {
        
            //apressio.Bluetooth
            apressio.BluetoothReader bt = 
               new apressio.BluetoothReader();
        }
    }
}

This strategy presents its own set of issues; summarily we find that the new namespaces are no longer visible within that scope. The namespace alias qualifier, introduced in C# 2.0, is the appropriate measure given the scenario highlighted. The example below shows how this can be accomplished:

using apressio = Apress.IO;
using apressdata = Apress.Data;
using aio = apressio;

namespace apressio
{
    public class TypeB
    {
    
    }
}

namespace apressdata
{
    public class TypeA
    {
    
    }
}

namespace Apress
{
    namespace Data
    {
        public class DataManager
        {
        
        }
    
        public class BluetoothReader
        {
        
        }
    }
    
    namespace IO
    {
        public class BluetoothReader
        {
        
        }
    }
}

namespace Aliases
{
    class Program
    {
        static void Main(string[] args)
        {
            apressio::BluetoothReader bt = 
                new apressio::BluetoothReader();
            aio::TypeB tb = new aio::TypeB();
        }
    }
}

The namespace alias qualifier can be used as follows:

<Left operand> ::  < right operand>

where left operand can be a namespace alias, an extern, or the global identifier. Right hand operand must be a type. Using the namespace alias qualifier with an alias that references a type causes a compile-time error.

global

global is not a keyword or identifier, but when used in tandem with the namespace alias qualifier, the global namespace alone is searched for the right hand identifier. The global identifier can be used as follows.

global::apressio.TypeB b = new apressio.TypeB(); //use of global
global::System.IO.DirectoryInfo info = 
                  new System.IO.DirectoryInfo("c:/");

extern

Believe it or not, problems are still lurking in the woodwork. Common sense and a strict compiler prevent us from creating situations like the one defined below where two distinct types share the same qualified name within the same assembly:

namespace apressio
{
    public class TypeB
    {
    
    }
}

namespace apressio
{
    public class TypeB
    {
    
    }
}

There is; however, nothing that prevents this exact scenario in two distinct assemblies.

//Apress1.dll
namespace apressio
{
    public class TypeB
    {
    
    }
}

Apress2.dll
namespace apressio
{
    public class TypeB
    {
    
    }
}

This of course, isn’t a problem until we run into a situation where both assemblies are referenced. Since all referenced assembly types along with all types in the running program are loaded into the same single namespace hierarchy, when we try to build our consuming program, everything breaks. The scenario described is an all too real problem in the modern day programming world, if not for any other reason than great minds thinking alike. (Referencing multiple versions of the same assembly can cause this as well). Fortunately, with the release of C# 2.0 comes the facility to handle multiple namespace hierarchies, implemented through the extern keyword and compile time configuration.

Utilizing extern aliases is a two step process. The first is to declare the hierarchies in our code using the extern alias keyword. The sample below illustrates.

extern alias ApressLibrary1;
extern alias ApressLibrary2;

extern alias declarations must not be preceded by anything else so these would go at the top of the file where they are to be used.

extern alias ApressLibrary1;
extern alias ApressLibrary2;
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using apressio = Apress.IO;
using apressdata = Apress.Data;
using aio = apressio;

namespace Aliases
{
    class Program
    {
        static void Main(string[] args)
        {
            //code that references two seperate TypeB 
            //definitions
            //will go here
        }
    }
}

The next step can be done in two different ways. From the command line we would define the aliases during compilation as follows:

[Editor comment: Line breaks used to avoid scrolling.]

csc /r:ApressLibrary1= ApressLibrary.dll /
   r: ApressLibrary2= ApressLibrary2.dll Aliases.cs

This step can also be achieved using Visual Studio 2005 integrated development environment by modifying the Aliases property of the referenced assembly, which always defaults to global, to the values ApressLibrary1 and ApressLibrary2 for ApressLibrary1.dll and ApressLibrary2.dll respectively. The referenced assemblies properties tab can be reached by viewing the standard properties window while selecting a referenced assembly. The diagram below shows the initial Alias of a referenced assembly:

For ApressLibrary1 the properties tab would be modified to this:

And for ApressLibrary2 the properties tab would be modified to this:

We now have two root namespace hierarchies that can be accessed uniquely. The code below illustrates their use:

extern alias ApressLibrary1;
extern alias ApressLibrary2;
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace Aliases
{
    class Program
    {
        static void Main(string[] args)
        {
            ApressLibrary1::apressio.TypeB typeB = 
                    new ApressLibrary1::apressio.TypeB();
            ApressLibrary2::apressio.TypeB typeB2 = 
                    new ApressLibrary2::apressio.TypeB();
        }
    }
}

The example above defines the extern alias ApressLibrary1 to be the root of a namespace hierarchy formed by the types in ApressLibrary1.dll and ApressLibrary2 to be the root of a namespace hierarchy formed by the types in ApressLibrary2.dll. TypeB can now be accessed using the namespace qualifier syntax without name collisions.

Whereas the command line alias declaration is achieved by utilizing the /r switch multiple times, (to reference the same assembly with multiple aliases for instance), Visual Studio 2005 allows for multiple aliases to be presented by accepting a comma delimited string in the Aliases property. We could then place an assembly in the global namespace as well as in an extern alias and be accessed in either manner. In the example below, the assembly ApressLibrary2.dll is referenced into the global namespace and into the ApressLibrary2 namespace.

The TypeB found in apressLibrary2.dll can now be accessed through the ApressLibrary2 extern alias or through the global namespace alias. The example below illustrates:

extern alias ApressLibrary1;
extern alias ApressLibrary2;
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace Aliases
{
    class Program
    {
        static void Main(string[] args)
        {
            ApressLibrary1::apressio.TypeB typeB = 
                  new ApressLibrary1::apressio.TypeB();
            ApressLibrary2::apressio.TypeB typeB2 = 
                  new ApressLibrary2::apressio.TypeB();
            apressio.TypeB typeB3 = new apressio.TypeB(); 
        }
    }
}

Once an extern alias is defined, it can be used as any standard namespace. The example below illustrates:

extern alias ApressLibrary1;
extern alias ApressLibrary2;
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace Aliases
{
    using ApressLibrary1::Apress.Data;
    using io = ApressLibrary2::apressdata.TypeA;
    class Program
    {
        static void Main(string[] args)
        {
            ApressLibrary1::apressio.TypeB typeB = 
                   new ApressLibrary1::apressio.TypeB();
            ApressLibrary2::apressio.TypeB typeB2 = 
                   new ApressLibrary2::apressio.TypeB();
            apressio.TypeB typeB3 = new apressio.TypeB();
            io typeA = new io();
            BluetoothReader blueReader = 
                            new BluetoothReader();
        }
    }
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Edward Moemeka

United States United States
Hi I'm Edward Moemeka,
For more interesting articles about stuff check out my blog at http://moemeka.blogspot.com
To correspond, email me at edward.moemeka@synertry.com
To support my company, thus help me feed my family, check out our awesome online preview at www.synertry.com. Remember, its in alpha Wink | ;-)

Comments and Discussions

 
QuestionGlobal Class Aliases PinmemberTheToid5-May-10 19:05 
GeneralGood Description -&gt; No Solutions Pinmembercbertolasio25-Jul-08 11:19 
QuestionAt runtime? PinmemberAnthonyLloyd304-Oct-05 9:30 
AnswerRe: At runtime? PinmemberVyas Bharghava8-Oct-07 3:54 
GeneralInteresting article. PinmemberPatrik Svensson4-Oct-05 8:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140821.2 | Last Updated 3 Oct 2005
Article Copyright 2005 by Edward Moemeka
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid