Namespaces

A namespace is a domain within which type names must be unique. Types are typically organized into hierarchical namespaces—both to avoid naming conflicts and to make type names easier to find. For example, the RSA type, which handles public key encryption, is defined within the following namespace:

	System.Security.Cryptography

A namespace forms an integral part of a type’s name. The following code calls RSA’s Create method:

	System.Security.Cryptography.RSA rsa =
	  System.Security.Cryptography.RSA.Create( );

Note

Namespaces are independent of assemblies, which are units of deployment such as an .exe or .dll. Namespaces also have no impact on member visibility—public, internal, private, and so on.

The namespace keyword defines a type within a namespace. For example:

	namespace Outer.Middle.Inner
	{
	  class Class1 {}
	  class Class2 {}
	}

The dots in the namespace indicate a hierarchy of nested namespaces. The following is semantically identical to the preceding example:

	namespace Outer
	{
	  namespace Middle
	  {
	    namespace Inner
	    {
	      class Class1 {}
	      class Class2 {}
	    }
	  }
	}

You can refer to a type with is fully qualified name, which includes all namespaces from the outermost to the innermost. For example, we could refer to Class1 in the preceding example as Outer.Middle.Inner.Class1.

Types not defined in any namespace are said to reside in the global namespace. The global namespace also includes top-level namespaces, such as Outer in our example.

The using Directive

The using directive imports a namespace. This is a convenient way to refer to types without their fully qualified names. For example:

	using Outer.Middle.Inner;

	class Test    // Test is in the global namespace
	{
	  static void Main( )
	  {
	   Class1 c;    // Don't need fully qualified name
	  }
	}

A using directive can be nested within a namespace itself to limit the scope of the directive.

Rules Within a Namespace

Name scoping

All names present in outer namespaces are implicitly imported into inner namespaces. In this example, the names Middle and Class1 are implicitly imported into Inner:

	namespace Outer
	{
	  namespace Middle
	  {
	    class Class1 {}

	    namespace Inner
	    {
	      class Class2 : Class1 {}
	    }
	  }
	}

If you want to refer to a type in a different branch of your namespace hierarchy, you can use a partially qualified name. In the following example, we base SalesReport on Common.ReportBase:

	namespace MyTradingCompany
	{
	  namespace Common
	  {
	    class ReportBase {}
	  }
	  namespace ManagementReporting
	  {
	    class SalesReport : Common.ReportBase {}
	  }
	}

Name hiding

If the same type name appears in both an inner and outer namespace, the inner name wins. To refer to the outer type, you must use its fully qualified name.

Note

All type names are converted to fully qualified names at compile time. Intermediate Language (IL) code does not contain any unqualified or partially qualified names.

The global:: qualifier

Occasionally, a fully qualified type name may conflict with an inner name. You can force C# to use the fully qualified type name by prefixing it with global:: as follows:

global:: System.Text.StringBuilder sb;

Repeated namespaces

You can repeat a namespace declaration, as long as the type names within the namespaces don’t conflict:

	namespace Outer.Middle.Inner { class Class1 {} }
	namespace Outer.Middle.Inner { class Class2 {} }

Aliasing Types and Namespaces

Importing a namespace can result in type-name collision. Rather than importing the whole namespace, you can import just the specific types you need, giving each type an alias. For example:

	using PropertyInfo2 = System.Reflection.PropertyInfo;

	class Program { PropertyInfo2 p; }

An entire namespace can be aliased, as follows:

	using R = System.Reflection;

	class Program { R.PropertyInfo p; }
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset