Defining Namespaces

As mentioned in Chapter 2, all data types are identified by the combination of their namespace and their name. However, in the CLR, there is no such thing as a “namespace.” The type’s name actually is the fully qualified type name, including the namespace. For the classes you defined earlier, there was no explicit namespace declaration. Classes such as these are automatically declared as members of the default global namespace. It is likely that such classes will experience a name collision, which occurs when you attempt to define two classes with the same name. Once you begin referencing other assemblies from third parties, the likelihood of a name collision increases even further.

More important, there are thousands of types in the CLI framework and multiple orders of magnitude more outside the framework. Finding the right type for a particular problem, therefore, could potentially be a significant challenge.

The resolution to both of these problems is to organize all the types, grouping them into logical related categories called namespaces. For example, classes outside the System namespace are generally placed into a namespace corresponding with the company, product name, or both. Classes from Addison-Wesley, for example, are placed into an Awl or AddisonWesley namespace, and classes from Microsoft (not System classes) are in the Microsoft namespace. The second level of a namespace should be a stable product name that will not vary between versions. Stability, in fact, is key at all levels. Changing a namespace name is a version-incompatible change that should be avoided. For this reason, you should avoid using volatile names (organization hierarchy, fleeting brands, and so on) within a namespace name.

Namespaces should be labeled using PascalCase, but if your brand uses nontraditional casing, it is acceptable to use the brand casing. (Consistency is key, so if that will be problematic—with PascalCase or brand-based casing—favor the use of whichever convention will produce the greater consistency.) You use the namespace keyword to create a namespace and to assign a class to it, as shown in Listing 10.9.

Listing 10.9: Defining a Namespace
// Define the namespace AddisonWesley
namespace AddisonWesley
{
    class Program
    {
        // ...
    }
}
// End of AddisonWesley namespace declaration

All content between the namespace declaration’s curly braces will then belong within the specified namespace. In Listing 10.9, for example, Program is placed into the namespace AddisonWesley, making its full name AddisonWesley.Program.

note
In the CLR, there is no such thing as a “namespace.” Rather, the type’s name is the fully qualified type name.

Like classes, namespaces support nesting. This provides for a hierarchical organization of classes. All the System classes relating to network APIs are in the namespace System.Net, for example, and those relating to the Web are in System.Web.

There are two ways to nest namespaces. The first approach is to nest them within one another (similar to classes), as demonstrated in Listing 10.10.

Listing 10.10: Nesting Namespaces within One Another
// Define the namespace AddisonWesley
namespace AddisonWesley
{
    // Define the namespace AddisonWesley.Michaelis
    namespace Michaelis
    {
        // Define the namespace
        // AddisonWesley.Michaelis.EssentialCSharp
        namespace EssentialCSharp
        {
            // Declare the class
            // AddisonWesley.Michaelis.EssentialCSharp.Program
            class Program
            {
                // ...
            }
        }
    }
}
// End of AddisonWesley namespace declaration

Such a nesting will assign the Program class to the AddisonWesley.Michaelis.EssentialCSharp namespace.

The second approach is to use the full namespace in a single namespace declaration in which a period separates each identifier, as shown in Listing 10.11.

Listing 10.11: Nesting Namespaces Using a Period to Separate Each Identifier
// Define the namespace AddisonWesley.Michaelis.EssentialCSharp
namespace AddisonWesley.Michaelis.EssentialCSharp
{
    class Program
    {
        // ...
    }
}
// End of AddisonWesley namespace declaration

Regardless of whether a namespace declaration follows the pattern shown in Listing 10.10, that in Listing 10.11, or a combination of the two, the resultant CIL code will be identical. The same namespace may occur multiple times, in multiple files, and even across assemblies. For example, with the convention of one-to-one correlation between files and classes, you can define each class in its own file and surround it with the same namespace declaration.

Given that namespaces are key for organizing types, it is frequently helpful to use the namespace for organizing all the class files. For this reason, it is a good idea to create a folder for each namespace, placing a class such as AddisonWesley.Fezzik.Services.RegistrationService into a folder hierarchy corresponding to the name.

When using Visual Studio projects, if the project name is AddisonWesley.Fezzik, you should create one subfolder called Services into which RegistrationService.cs is placed. You would then create another subfolder (Data, for example) into which you place classes relating to entities within the program (RealestateProperty, Buyer, and Seller, for example).

Guidelines
DO prefix namespace names with a company name to prevent namespaces from different companies having the same name.
DO use a stable, version-independent product name at the second level of a namespace name.
DO NOT define types without placing them into a namespace.
CONSIDER creating a folder structure that matches the namespace hierarchy.
{{ snackbarMessage }}