Every application begins with a namespace in C# .NET that has the same name as the project. Of course, you can change the namespace to anything you like in order to maintain compatibility with other projects.

For example we declared namespace Mycplus.CSharpBasics while taking an Overview of C#. We can write the whole application with in one namespace or we can declare multiple namespaces as needed in our project. The general syntax of declaring a namespace is

Why use namespaces?

Nothing in the C# standard says you must use namespaces. You can create classes by themselves and use them as needed. The point behind using namespaces is organization. Using a namespace enables you to gather all of the classes you create in one place, even if they exist in separate files. In addition, using namespaces helps avoid potential name clashes between vendors. If two vendors choose the same name for a class, then C# will constantly flag ambiguous references in your code.

The namespace isn’t a one-level phenomenon. You can use several levels of namespaces to organize your code. In fact, Microsoft followed this procedure when creating the .NET Framework. Look at the System namespace and you’ll see it contains several levels of other namespaces.

Creating multiple levels of namespaces in your own code is relatively easy. All you need to do is define a namespace within the confines of another namespace as shown here:

Notice that the Sample namespace contains a combination of classes and namespaces. You can mix and match classes and namespaces as needed to achieve your organizational goals. The important consideration is keeping the classes organized so they’re easy to find.

Constructors & Destructors

Any class you create should include a constructor, even if the constructor is empty. A constructor enables a client to create an instance of the object that the class defines. The constructor is the starting point for your class. We’ve already looked at several constructors in the chapter. As you’ve seen, constructors never provide a return value, but they can accept one or more input parameters.

One of the issues we haven’t discussed is the use of multiple constructors. Classes with multiple constructors are quite common because the multiple constructors enable a client to create objects in more than one way. In addition, many classes use overrides as a means for handling optional parameters. One of the better examples of this second form of constructor is the MessageBox.Show() method, which has 12 overrides that enable you to use different types of optional parameters. Here’s an example of an application that relies on a class with multiple constructors.

The example application uses these three constructors to open three versions of a secondary form. As you can see, each constructor adds another optional parameter. The example works equally well with any of the constructors. However, adding more information results in a more functional display.

Working with Destructors

Given the way that C# applications work, you’ll almost never need to add a destructor to any code. A destructor works differently in the .NET environment than in previous Windows environments in that you can’t be sure when the destructor will get called. The Garbage Collector frees class resources, at some point, after the class is no longer needed.

The C# specification does allow for a destructor. The destructor can’t have any return value, nor can it accept any input values. This means you can’t override the destructor, so there’s at most one destructor for any given class. In addition, a class can’t inherit a destructor, which means you must create a unique destructor for each class you create (if one is desired).

Destructors should avoid making time-critical changes to the user environment, and they should not use resources that might not be available at the time the destructor is called. For example, you wouldn’t want to display a completion message from the destructor because the user might be engaged in some other activity. Likewise, you wouldn’t want to attempt to close a file handle from the destructor because the file resource might not exist.

Garbage Collector (GC)

Every C# program has access to the GC (Garbage Collector) object. You can tell the Garbage Collector to run when it’s convenient for you. However, the garbage collection process doesn’t just involve your application. If you start the garbage collection process, the Garbage Collector will examine the resources for every running application?a huge performance penalty in some situations. The garbage collection could also occur at an inconvenient time. Time-critical processes could get interrupted when you force a garbage collection at the wrong time. The following code shows how to force a garbage collection, but you should use this feature with extreme care.

Using Preprocessing Directives

Anyone who’s used Visual C++ will know the value of preprocessing directives. C# provides a limited number of preprocessing directives that control the flow of compilation, but don’t provide the same level of functionality that Visual C++ provides because C# lacks a true preprocessor. In short, you can use the preprocessor to add or subtract features based on the current configuration, but you can’t perform some of the other tasks that Visual C++ can perform.

Preprocessing Directives Supported by C#
Directive Description Example
#define Creates a symbol used for conditional statements such as #if. Never use a variable name for a #define #define DEBUG
#elif Enables conditional compilation if the selected condition is true and the associated #if condition is false. Use this directive in place of #else if you need to test more than one condition. Uses the same operators as the #if directive. #elif (DEBUG)
#else Enables conditional compilation if the associated #if condition is false. #else
#endif Ends conditional compilation started with an #if directive. #endif
#endregion Ends a region created with the #region directive. #endregion
#error Generates an error message. This directive is normally associated with the #if directive to turn the error generation on and off. #error This is an error message.
#if Enables conditional compilation if the selected condition is true. You can test for equality (==) and inequality (!=). The #if directive also supports both and (&&) and or (||). Using #if without operators tests for the existence of the target symbol. #if (DEBUG)
#line Modifies the current line number. You can also add an optional filename. Using default in place of a number returns the embedded numbering system to its default state. #line 200 or # line default or #line 20 “MyFilename”
#region Creates a region block within the IDE. Each region block has an associated collapse feature so you can hide of display the region. You can’t overlap a region with an #if directive. However, the #if can contain the region or the region can contain the #if. #region MyRegionName
#undef Deletes a symbol created with the #define directive. #undef DEBUG
#warning Generates a warning message. This directive is normally associated with the #if directive to turn the error generation on and off. #warning This is a warning message.