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, however, 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. Namespaces may include a period in the name, and doing so 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. 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. While generally namespaces should be labeled using PascalCase, 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 File-Scoped Namespace
// Define the namespace AddisonWesley.Michaelis.EssentialCSharp
namespace AddisonWesley.Michaelis.EssentialCSharp;
class Program
{
    // ...
}

A file-scoped namespace declaration (added in C# 10.0) has a statement like syntax with the ending semicolon. The file-scoped namespace declaration must precede all other member definitions in the file and there can be only one such declaration. And, given the declaration, all members within the file will be assigned to that namespace. In Listing 10.9, for example, Program is placed into the namespace AddisonWesley.Michaelis.EssentialCSharp, making its full name AddisonWesley.Michaelis.EssentialCSharp.Program. If you are programming in C# 10.0 or later, I recommend using this form. It cuts down on unnecessary indentation and handles all standard cases of namespace declaration. Additionally, except for HelloWorld scenarios, you should specify a namespace for all your types.

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

Prior to C# 10, namespace declarations used curly braces to identify the scope as demonstrated in Listing 10.10.

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

All content between the namespace declaration’s curly braces will then belong within the specified namespace. Declaring a namespace using curly braces allows multiple namespace declarations it to occur in a single file. However, given the guideline of one-to-one correlation between files and type definitions (i.e., one class per file), it would be unusual to have multiple namespaces in the same file.

AdVanced Topic
Nesting Namespaces

Like classes, namespaces declared using curly braces support nesting. In the examples so far, the hierarchy of namespaces is defined simply using a period in the namespace name. However, it is also possible to define the hierarchy using nesting within the curly braces (similar to classes), as demonstrated in Listing 10.11.

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

All three namespace related listings (Listing 10.9 - Listing 10.11) will assign the Program class to the AddisonWesley.Michaelis.EssentialCSharp namespace.

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. For example, 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 use file-scoped namespaces (C# 10.0 or later).
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 }}
;