#988 – Using global to Explicitly Refer to a Namespace

A fully qualified namespace is not always sufficient to refer to a type.  Below, we’ve (unwisely) declared two different classes named Utility–a subclass of Program in the ConsoleApplication1 namespace and a class in the Program namespace.

If we refer to Program.Utility from within the Main method, the subclass is used.  To use the other version of Utility, we need to use the global keyword to describe the exact path to the type.  global::Program refers to the top-level namespace Program.

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            // Class Program.Utility in namespace ConsoleApplication1
            Program.Utility util = new Program.Utility();

            // Class Utility in namespace Program
            global::Program.Utility util2 = new global::Program.Utility();
        }

        class Utility
        {
            public Utility()
            {
                Trace.WriteLine("Class Program.Utility in namespace ConsoleApplication1");
            }
        }
    }

}

namespace Program
{
    public class Utility
    {
        public Utility()
        {
            Trace.WriteLine("Class Utility in namespace Program");
        }
    }
}
Advertisements

#711 – The Global Namespace

Types and namespaces are normally defined within a namespace, creating a hierarchy of namespaces which in turn contain types.

In the example below, the ConsoleApplication1 namespace contains the Program type.

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hi");
        }
    }
}

This structure will appear in the IL Disassembler as shown below. Note that the fully qualified name of the Program type includes the namespace.

You can also declare a type that is not inside of a namespace.  The type will instead be declared as part of what’s known as the global namespace.  In the example below, the Program type is declared directly in the global namespace.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Hi");
    }
}

This appears in the IL Disassembler as:

#533 – Alternate Notation for Extern Aliases

You can use identically named types that come from different assemblies by setting up an extern alias and then using that alias to qualify the type names.

Once you’ve set up an extern alias, there are two different syntax variations that you can use in qualifying type names from an aliased assembly.  You can use either a colon (:) or a dot (.) after the alias.

    extern alias AnotherLib;

    class Program
    {
        static void Main()
        {
            // Syntax variant #1
            AnotherLib::DogLibrary.Dog d2 = new AnotherLib::DogLibrary.Dog("JRT", "Jack");

            // Syntax variant #2
            AnotherLib.DogLibrary.Dog d3 = new AnotherLib.DogLibrary.Dog("Rough Collie", "Lassie");
        }
    }

#532 – Using Identically Named Types from Different Assemblies

If you want to use two types from different assemblies that have exactly the same name, including the namespace, your application won’t know which type to use.  The fully qualified type names are identical and you’ll get an error.

You can use both types in your project by providing an extern alias for the namespace hierarchy in one of the DLLs.

In Visual Studio, in your application, select the reference to one of the two assemblies.  Change the Aliases property from global to a new name.

Now include an extern alias statement in your code, using the same name.  Then use this alias to reference types in the aliased assembly.

using DogLibrary;   // FirstDogLibrary.dll

namespace ConsoleApplication1
{
    extern alias AnotherLib;

    class Program
    {
        static void Main()
        {
            // DogLibrary.Dog in FirstDogLibrary.dll
            Dog d = new Dog("Kirby", 12);

            // DogLibrary.Dog in AnotherDogLibrary.dll
            AnotherLib::DogLibrary.Dog d2 = new AnotherLib::DogLibrary.Dog("JRT", "Jack");
        }
    }
}

#531 – Best Practices for Naming Namespaces

In C#, a namespace declaration specifies the name of the namespace and you can use any valid C# identifier as the name.  However, it’s generally considered good practice to follow the suggestions listed below when naming namespaces.

  • Use Pascal Casing for each portion of the namespace, capitalizing the first letter of each word.  E.g. Acme.AfricanAnimalLibrary
  • Do not use underscores
  • Use sub-namespaces to organize/group related namespaces
  • The highest two levels of namespaces should follow the pattern CompanyName.ProductName or CompanyName.TechnologyName.  E.g. Acme.SearchEngine.Logging or Acme.Rendering.3DTools


Incorporating your company or organization name into the namespace hierarchy helps ensure that your types are globally unique.

#530 – Namespaces vs. Assemblies

In .NET, code is organized into both assemblies and namespaces.

  • An assembly is a physical file containing a number of types (.exe or .dll)
  • namespace is a logical grouping representing a parent name that various types belong to

An assembly can contain types belong to one or more namespaces.  Types belonging to a single namespace can be contained in a single assembly, or spread across multiple assemblies.

Code can reference types within another assembly after including a reference to that assembly in the current project.

Code can reference types in another namespace by using the full name of the type that includes the namespace, or with an using directive.

The example below shows two assemblies, both .DLL files, containing some types.  Each assembly contains types belonging to more than one namespace.  And each namespace shown is spread across both assemblies.

#529 – The using Directive Can Create an Alias for a Namespace

The most common use of the using directive is to bring types within a specified namespace into scope, so that they can be referenced directly in your code.

using DogLibrary;
using DogLibrary.Utility;

You can also use the using directive to create an alias for a namespace, which you can then use to access the types in that namespace.

In the example below, we have two different namespaces that each contain a DogLogger type.  Instead of having to list the fully qualified name of either DogLogger type when we use it, we can assign a shorter alias to refer to the containing namespace.

using U1 = DogLibrary.Utility.StandardLogging;
using U2 = DogLibrary.Utility.AlternateLogging;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            // Short for DogLibrary.Utility.StandardLogging.DogLogger
            U1.DogLogger log1 = new U1.DogLogger(@"C:\log1.txt");

            // Short for DogLibrary.Utility.AlternateLogging.DogLogger
            U2.DogLogger log2 = new U2.DogLogger(@"C:\log2.txt");
        }
    }
}