Namespaces vs Assemblies

The .NET Framework organizes classes (types) in two different levels: namespaces and assemblies. We’ll take a look at the differences between both of them in this post.

Assemblies

An assembly is the physical unit that contains .NET compiled code (classes).

Even though an assembly can be stored in multiple files, it’s easier to think of an assembly as a single file with .NET code. In the .NET Framework, all of our classes (types) exist in assemblies.

Every time you compile an application or a class library, an assembly is created. The assembly can be an executable (.exe file) or a library (.dll file). The only difference is that the executable contains an entry point so that it can be executed by Windows. Libraries are accessed by executables.

Assemblies have a version number expressed in the format: <major version>.<minor version>.<build number>.<revision number>. For example, an assembly might have the version number 2.6.2000.30.

Every assembly contains metadata with information about itself and the classes it contains. This is called assembly manifest. The assembly manifest contains primarily the following information:

  1. The assembly name
  2. Version number
  3. Culture and language supported by the assembly
  4. Information about the classes contained in the assembly
  5. A list of other assemblies that this assembly references

The assembly manifest is used when we need to use classes from another assembly in our code. Because an assembly is able to describe itself, it doesn’t need to use the Windows Registry to make its classes available to other assemblies. This makes .NET a way better option than using COM, where newer versions of a component could break the applications using an older version.

An AssemblyInfo.cs file (or .vb if you’re using Visual Basic) is created inside the special folder Properties by Visual Studio when you create a new project. This file contains general information about the assembly, such as title, description, company, copyright and trademark.

In this file, we can also specify the assembly version we want to use. Here’s an example:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SampleApp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("My Company")]
[assembly: AssemblyProduct("SampleApp")]
[assembly: AssemblyCopyright("Copyright © My Company 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("61275b5f-3883-41bb-87fc-79648a6fe2b7")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Please note that the assembly version could be different than the file version. The assembly version is used by the .NET Framework. The file version is what you can see in Windows when you view the file properties.

If you want to have different build and revision numbers every time you build the project, you can have the compiler do it for you by using the “*” symbol, as shown in the code comments above. It will increment the number for you automatically on every compilation.

Private Assemblies and Shared Assemblies

Assemblies can be deployed with your application as private or as shared.

Private assemblies are intended to be used only by one application. This is the normal behavior.

All the executables and libraries that an application needs are copied to the application’s own folder in the Program Files directory. This way, different applications could have a different version of the same assembly. When an application needs to be updated, the corresponding assemblies are just replaced, and other applications won’t be affected.

When you need to make your code available to multiple applications, your assemblies can be deployed as shared, instead of being copied multiple times.

In order for the shared assembly to be available for any application to use, it needs to be placed in a special directory known as Global Assembly Cache (GAC). Assemblies cannot just be copied to this directory. It is necessary to use one of the following tools:

  • Microsoft Windows Installer
  • Gacutil.exe tool
  • NET Framework Configuration Tool. This option was removed in .NET 4.

Namespaces

A namespace is a logical unit of classes and types. Namespaces are not a replacement of assemblies but rather a complement. Every class is part of an assembly and of a namespace. You could also have two classes that are part of the same namespace but pertain to different assemblies.

Namespaces are used to avoid name collisions. If you have two classes with the same name but different functionality, you would place each class in a different namespace. Any time you need to use one of them, you just reference the appropriate namespace.

Namespaces can contain other namespaces. This creates a hierarchy of namespace and classes with multiple levels.

Take as an example the .NET Framework Base Class Library. All the classes in this library are in the root namespace System. And inside the System namespace you can find the Windows namespace, with classes targeted to build desktop applications. Also inside the System namespace is the Web namespace, with classes targeted to build web applications. Within each namespace, you’ll find more namespaces with classes for more specific functionality.

In the project properties, you define the default namespace you want to use for all the classes in the project, which will usually be the name of the project. All of the classes in the project will be part of the default namespace, unless you define another namespace when declaring your classes. In C#, you would do it like this:

namespace MyApp
{
	namespace MyProject
	{
		using System;

		class MyClass
		{
			public static void Main()
			{
				Console.WriteLine("Hello World!");
			}
		}
	}
}

In this code, the MyClass class is inside the MyProject namespace, which is at the same time inside the namespace MyApp.

We could also declare the nested namespaces like this:

namespace MyApp.MyProject
{
	using System;

	class MyClass
	{
		public static void Main()
		{
			Console.WriteLine("Hello World!");
		}
	}
}

The fully qualified name of you class would be MyApp.MyProject.MyClass.

To reference a class in another namespace, you could either use the fully qualified name or you can import the namespaces that you want to use. In the samples above, we import the System namespace with the keyword using (imports in Visual Basic).

We could also have called the WriteLine function like this:

System.Console.WriteLine(“Hello World!”);

So every time we need to use a class in our code, we need to reference the assembly containing the class, if it’s not part of the same project, and we also need know the namespace where the class is located and import it.

Please leave a comment if you have any question.

Get Free Updates
Related Posts
Comments