developmentor - a developer services company				  
				      C# Tutorial
   Modules

Namespace


Goals:

  • Show how to create a namespace.
  • Show how to access a type defined within a namespace.
  • Discuss the advantages of organizing code into namespaces.

Overview

A namespace provides a container for a group of types. Related types are placed inside the same namespace to produce a clean and logical organization of code. Namespaces help to avoid type name collisions by creating distinct scopes.


Motivation - logical grouping

It is common for a group of types to be logically related. For example, a model of people at a university would likely have types such as person, student, employee, undergraduate, etc. A drawing application would have types like shape, circle, rectangle, and line. Grouping the related types into a namespace cleanly partitions the source code. It also makes things more convenient for clients because it can greatly simplify their search for a needed class.


Motivation - name collision

It sometimes happens that two programmers use the same type name. The chance of this increases as the project size grows or when multiple libraries from third party vendors are utilized. Two types with the same name cannot exist in the same scope. The code below shows the problem. It will be a compile time error to use the two Shape classes in the same program.

Placing the two Shape classes in different namespaces will resolve the issue.


Creating a namespace

The most basic way to create a namespace is to use the keyword namespace, give the name of the namespace, and then define the namespace body. The body contains a group of types inside curly braces. The figure below demonstrates the basic syntax by creating a Shapes namespace containing four classes.

Defining an entire namespace in one place forces all the types to be defined in a single file which makes it difficult for multiple programmers to work on the code. It is more common to define the namespace in many separate parts and let the pieces be logically merged together into a single namespace by the compiler. The syntax is shown below. Notice how each class is defined in its own file and placed inside its own namespace declaration. This way of defining a namespace is logically equivalent to defining the entire namespace at once.


Access to namespace members

Accessing types defined inside a namespace requires just a little extra thought. There are two cases to consider because the client code could either be inside the same namespace or outside. The following logical representation of the Shapes namespace summarizes the issue.

If the client code is inside the same namespace then there is no extra work to do and the short name of the class can be used.

If the client code is outside the namespace, then the fully qualified name of the class is used. The fully qualified name is formed from the namespace name, the dot operator, and the short name of the class.

Typing fully qualified names quickly becomes tedious. A using directive eliminates the need for fully qualified names by bringing all the types from a namespace into the local scope.


Using alias

The keyword using can also create an alias for either a class or a namespace. This technique is not common, but it is occasionally useful to resolve ambiguities or to provide a way to easily switch between different namespaces so it is worth a quick look. Let's first examine a using alias for a class. The syntax to create an alias is "using newName = oldName;". The new name can then be used in place of the old name.

An alias for a namespace can be created with the syntax "using newNamespace = oldNamespace;". The new name can then be used as a namespace name. The compiler will translate the alias into the namespace name it really represents.


Nested namespace

Namespaces that are only one level deep are not generally sufficient to logically organize code. Consider the Shapes namespace. Should all geometric shapes be placed in the single namespace or might it be better to subcategorize the geometric types according to some other property such as whether they are a two or three dimensional shape? Furthermore, if two different programmers accidentally use the same namespace name then the names will collide. To better guarantee uniqueness and to more finely categorize their contents, namespaces can be nested.

The most basic syntax to create a nested namespace is to define one namespace inside another as shown below. This syntax is considered a bit verbose and is not used very often in practice.

The preferred way to define a nested namespace is the shorthand syntax using the dot operator.

The fully qualified name for a member of a nested namespace consists of each namespace name and the class name with each component separated by the dot operator. It is common to encounter five or six levels of namespace nesting so a using directive is often the better choice.


Global namespace

Types that are not defined inside any namespace are placed in the "global namespace". Members of the global namespace are available for use in all other namespaces with no prefixing required. The common wisdom says to minimize your impact on the global namespace because each symbol you add to the global namespace increases the likelihood of a name collision.

This material is excerpted from the Programming C# course offered by DevelopMentor.