Namespaces in C#

Before moving on, it ’ s worthwhile to consider one more important subject — namespaces . These are the .NET way of providing containers for application code, such that code and its contents may be uniquely identified. Namespaces are also used as a means of categorizing items in the .NET Framework. Most of these items are type definitions, such as the simple types ( System.Int32 and so on).
 
C# code, by default, is contained in the global namespace . This means that items contained in this code are accessible from other code in the global namespace simply by referring to them by name. You can use the namespace keyword, however, to explicitly define the namespace for a block of code enclosed in curly brackets. Names in such a namespace must be qualified if they are used from code outside of this namespace.
 
A qualified name is one that contains all of its hierarchical information, which basically means that if you have code in one namespace that needs to use a name defined in a different namespace, you must include a reference to this namespace. Qualified names use period characters ( . ) between namespace levels, as shown here:


namespace LevelOne
{
// code in LevelOne namespace
// name “NameOne” defined
}
// code in global namespace

This code defines one namespace, LevelOne , and a name in this namespace, NameOne (no actual code is shown here to keep the discussion general; instead, a comment appears where the definition would go). Code written inside the LevelOne namespace can simply refer to this name using NameOne — no classification is necessary. Code in the global namespace, however, must refer to this name using the classified name LevelOne.NameOne.
 
Within a namespace, you can define nested namespaces, also using the namespace keyword. Nested namespaces are referred to via their hierarchy, again using periods to classify each level of the hierarchy. This is best illustrated with an example. Consider the following namespaces:

namespace LevelOne
{
// code in LevelOne namespace
namespace LevelTwo
{
// code in LevelOne.LevelTwo namespace
// name “NameTwo” defined
}
}
// code in global namespace

Here, NameTwo must be referred to as LevelOne.LevelTwo.NameTwo from the global namespace, LevelTwo.NameTwo from the LevelOne namespace, and NameTwo from the LevelOne.LevelTwo namespace.

The important point here is that names are uniquely defined by their namespace. You could define the name NameThree in the LevelOne and LevelTwo namespaces:

namespace LevelOne
{
// name “NameThree” defined
namespace LevelTwo
{
// name “NameThree” defined
}
}

This defines two separate names, LevelOne.NameThree and LevelOne.LevelTwo.NameThree , which can be used independently of each other.

After namespaces are set up, you can use the using statement to simplify access to the names they contain. In effect, the using statement says, “ OK, I ’ ll be needing names from this namespace, so don ’ t bother asking me to classify them every time. ” For example, the following code says that code in the LevelOne namespace should have access to names in the LevelOne.LevelTwo namespace without classification:

namespace LevelOne
{
using LevelTwo;
namespace LevelTwo
{
// name “NameTwo” defined
}
}

Code in the LevelOne namespace can now refer to LevelTwo.NameTwo by simply using NameTwo . Sometimes, as with the NameThree example shown previously, this can lead to problems with clashes between identical names in different namespaces (if you use such a name, then your code won ’ t compile — and the compiler will let you know that there is an ambiguity). In cases such as these, you can provide an alias for a namespace as part of the using statement:

namespace LevelOne
{
using LT = LevelTwo;
// name “NameThree” defined
namespace LevelTwo
{
// name “NameThree” defined
}
}

Here, code in the LevelOne namespace can refer to LevelOne.NameThree as NameThree and LevelOne.LevelTwo.NameThree as LT.NameThree .

using statements apply to the namespace they are contained in, and any nested namespaces that might also be contained in this namespace. In the preceding code, the global namespace can ’ t use LT.NameThree . However, if this using statement were declared as :

using LT = LevelOne.LevelTwo;
namespace LevelOne
{
// name “NameThree” defined
namespace LevelTwo
{
// name “NameThree” defined
}
}

then code in the global namespace and the LevelOne namespace can use LT.NameThree .Note one more important point here: The using statement doesn ’ t in itself give you access to names in another namespace. Unless the code in a namespace is in some way linked to your project, by being defined in a source file in the project or being defined in some other code linked to the project, you won ’ t have access to the names contained. In addition, if code containing a namespace is linked to your project, then you have access to the names contained in that code, regardless of whether you use using . using simply makes it easier for you to access these names and can shorten otherwise lengthy code to make it more readable.