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.
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.
Prior to C# 10, namespace declarations used curly braces to identify the scope as demonstrated in Listing 10.10.
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.
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).