This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.

Understanding Namespaces

Rob Macdonald

Among the many new terms and concepts that .NET throws at you, "namespaces" is one concept that's worth getting comfortable with early on. Rob Macdonald has found that a lot of people shy away from grappling with namespaces because they seem like such an alien notion. It's true that namespaces are pretty abstract as concepts go, but actually there's not much to them. Swallow hard once, and you'll feel better forever, he advises.

Last month, I introduced assemblies. Now there's a big topic. Namespaces are "big" in that they appear everywhere in .NET, but small in terms of how much there is to know about them. I'll start with some Scottish history.

There was a clan leader called Donald, whose fine sons included Stuart, Andrew, Ian, and James. In the next glen lived Henry's clan. Henry's sons were Gordon, Stuart, Hamish, and Andrew. The two clans were friendly, and the clan leaders and their sons often got together to share a wee dram—or two—of whiskey. However, it got a bit confusing when Donald or Henry called on one of their sons to split open another haggis. Exactly which Stuart, or which Andrew, were they referring to? To clear things up, they invented surnames. Donald's son Stuart would be referred to as Stuart MacDonald ("Stuart, son of Donald"), and Henry's son Andrew would be referred to as Andrew MacHenry. From that time on, all male descendents of Donald would have the surname MacDonald. One writes articles for Visual Basic Developer. Another went on to sell billions of meat sandwiches worldwide.

In all honesty, this is fairly dubious history, but there is a point to it. Surnames are namespaces. They allow you to distinguish between two people who in everyday conversation have the same name. Technically, they address a problem known as "name pollution." There's nothing especially new about namespaces, though—even in computing. XML has them, and DBMSs like IBM's DB2 have had them for years.

In one sense, traditional COM objects also have namespaces. If you've been doing data access programming with VB for several years, you'll know that both DAO and ADO have an object called Recordset. If you're writing a program using only DAO, or using only ADO, there's no problem with simply declaring your variables "As Recordset." But what happens on those rare occasions when you need to reference both the DAO library and the ADO library in one program at the same time? The answer is that you prefix the class name with the library name as in this snippet:

'VB6 code
Dim adoRS As ADODB.Recordset
Dim daoRS As DAO.Recordset

Both COM and humans are a bit limited when it comes to getting the most out of namespaces, because they only have one level of name management. Every now and then I bump into another Rob Macdonald, and, frankly, things can get nasty. It can get even more unpleasant with COM objects (not that I bump into them very often).

.NET allows namespaces to be hierarchical, meaning that you can have namespaces within namespaces. Because namespaces can be hierarchical, it's easy to get them confused with inheritance—especially if both concepts are new to you. The reality is that there's no relationship between inheritance hierarchies and namespace hierarchies. Namespaces are simply ways of organizing names—nothing more. They have nothing to do with the functionality provided by the classes they contain.

Here's a simple example. In previous months, we've explored Windows Forms and Web Forms, both of which have a class called Button. From a user's perspective, buttons are simply things you click on to get something done, but internally, recognizing a click event and doing something based on a click are very different. One deals with HTTP/HTML, the other with the Win32 APIs. But it makes sense intuitively to call both of them "Button," and namespaces make this easy and unambiguous.

The Button on a Windows Form belongs to a namespace called System.Windows.Forms. It shares that namespace with other logically related classes such as ListBox, Label, and so on. The Button on a Web Form belongs to the namespace System.Web.UI.WebControls—which also contains ListBox and Label classes.

In the unlikely event that I'd want to create an application containing both a Web Form Button and a Windows Form Button, I can unambiguously create one of each like so:

Dim winButton As New System.Windows.Forms.Button
Dim webButton As New System.Web.UI.WebControls.Button

The System.Web.UI.WebControls namespace contains all of the major Web Controls. What happens if you jump up the hierarchy a bit? The System.Web.UI namespace is a namespace that contains two other namespaces—the WebControls one that we've already met and the HTMLControls namespace, which contains a whole set of HTMLControls that provide alternatives to using Web Controls on a Web Application. And the System.Web namespace? In addition to the UI namespace, it also contains a number of other namespaces to do with Web protocols and services. By supporting a hierarchical namespace system, .NET allows classes to be organized in a naming system that reflects the natural grouping of related components and avoids most of the potential for naming collisions.

Namespaces and assemblies

We've seen that namespaces have nothing to do with inheritance. It's a bit more difficult to accept that namespaces have nothing to do with assemblies either, though—especially because, at first glance, they seem to be closely related.

You'll recall from last month's column that assemblies are the physical components that contain classes. An assembly generated from Visual Studio.NET will either be one DLL or one EXE and will contain one or more classes. The point here is that classes physically exist in an assembly. In a completely different sense, classes also belong in a namespace, but this is just a convenient way of organizing names and has nothing to do with the physical implementation or storage of classes.

To make this clear, the classes that belong to one namespace can be implemented in several different assemblies. Equally, the classes implemented in one assembly can belong to several namespaces.

This sounds straightforward enough—the trouble is that when you look around the .NET Base Class libraries, it's easy to conclude that all of the classes that belong to one namespace are actually physically implemented inside one assembly. However, drawing this conclusion can make you very frustrated because it happens to not be true. For an example, take a look at Figure 1 and Figure 2. Figure 1 shows the Solution Explorer listing the references set to assemblies in a VB.NET Console Application. You can see there are physical references to the System.Data assembly and the System.XML assembly. Figure 2 shows the Object Browser, which has a node for each assembly referenced. The Object Browser organizes each assembly's classes by the namespace each class belongs to. To save space, I'm only showing one class (XmlDataDocument) in Figure 2. All of the other nodes you can see under System.Data and System.Xml are the namespaces their classes belong to. (I would need to expand to show all of the classes.)

At this point, it's easy to get confused. There's an assembly called System.Xml, but there's also a namespace called System.Xml. And then there are classes belonging to the System.Xml namespace that are physically contained in the System.Xml assembly. The System.Xml namespace is broken down into smaller namespaces such as System.Xml.Schema and System.Xml.Xpath. However, not all of the classes that belong in the System.Xml namespace are physically contained in the System.Xml assembly. Take a look at the System.Data assembly, and you'll see that the XmlDataDocument class belongs in the System.Xml namespace.

Pop quiz—to determine whether you're grasping this, ask yourself this question: If you want to use the XmlDataDocument class (that belongs in the System.Xml namespace), which assembly do you need to reference? The answer, of course, is the System.Data assembly. However, unless you remember that there's no enforced overlap between assemblies and namespaces, you wouldn't understand why the XmlDataDocument class isn't available to you after setting a reference to the System.Xml assembly.

Why, you ask, has Microsoft done this with the XmlDataDocument class? Well, as a class, it's clearly related to XML (it actually inherits from XmlDocument, the generic XML DOM in .NET). But its task is to allow an XML programmer to use an ADO.NET DataSet in an XML way rather than in an ADO way. Presumably, for implementation purposes, it needs to share some code that's contained in the System.Data assembly, so it makes sense for it to physically reside in the System.Data assembly, and yet at the same time to logically "belong" to the System.Xml namespace.

In a nutshell, while a namespace might give you a clue as to where a class is physically implemented, there are times when following this clue can be misleading. After all, not all MacDonalds can trace their ancestry back to Scotland (in my case, I'm not actually sure).

The Imports statement

I can understand why keeping namespaces and assemblies (and inheritance) as completely separate concepts can be helpful. I can understand why so many namespaces and assemblies actually have the same name. What I can't understand is why VB.NET calls this the "Imports" statement (the same feature in C# is called the "using" statement—which, as you'll see shortly, is about a million times more meaningful). However, before completing my rant on this topic, let's ignore the name for a moment and see what Imports does.

Earlier, I showed you these two lines of code:

Dim winButton As New System.Windows.Forms.Button
Dim webButton As New System.Web.UI.WebControls.Button

Very nice, but I really don't want to type System.Windows.Forms.Button each time I want to reference a Button. The Imports statement removes the need to do this. If I include the following at the top of a .vb code file, the compiler will allow me to use the name of any class within that namespace without needing to fully qualify its name:

Imports System.Windows.Forms

Therefore, I can simply declare:

Dim winButton As New Button

This is all Imports does. It's simply a shortcut for typing class names. It's easy to imagine that the Imports statement gives you access to the classes contained within an assembly. Easy, but not correct, because Imports has nothing to do with assemblies and everything to do with namespaces. To get access to the classes in an assembly, you need to physically reference that assembly via the Add References dialog. Then you can start working with those classes. Note that the Imports statement is always optional and only exists to save you typing (and perhaps to make your code more readable). It therefore doesn't import anything in any physical sense, and for this reason, I think the choice of keyword is extremely unfortunate, especially as C# uses a perfectly acceptable alternative.

If you've started working with Visual Studio, you've probably noticed that some Imports statements exist by default. It turns out that Visual Basic.NET projects use a different set of default Imports statements for each project type. Fortunately, you can examine them—and change them—via the Project Properties dialog, as shown in Figure 3.

Creating your own namespaces

Every class (and therefore every form, control, and so on) that you create in Visual Basic.NET belongs to a namespace. Usually, your classes belong to a namespace that has the same name as your project (which is also the name given by default to the assembly that will contain your classes). However, you can change the project-wide namespace used for all of your classes by using the Project Properties dialog as shown in Figure 4. Here, you can see that I've chosen to have all of my classes belong to a namespace that I've ever so imaginatively called MyNameSpace.

Being able to control the namespace like this can be useful. For example, I might want to create a namespace called "Math" but implement its functionality using two different assemblies (one for standard math functions, another for scientific functions, for example).

Alternatively, you can specify a namespace in code using the NameSpace keyword. The System.Data namespace contains a number of namespaces. For example, there's one called SqlClient, which allows ADO.NET code to connect directly to a SQL Server database. Another, called OleDb, allows ADO.NET programs to use existing OLE DB Providers (this namespace was called System.Data.ADO in Beta 1). I've decided it might be nice to add another namespace called DAO to System.Data. To do this, I've created a VB.NET Class Library application called DAOLib and have used the Project Properties dialog (see Figure 4) to blank out the root namespace for this project. I then created a class called DaoConnection with the following code:

Namespace System.Data.DAO
   Public Class DaoConnection
      Private connString As String
      Public Property ConnectionString() As String
         Get
            Return connString
         End Get
         Set(ByVal Value As String)
            connString = Value
         End Set
      End Property
   End Class
End Namespace

Notice that the DaoConnection class definition is completely contained within a namespace definition. What I've done here is add a new namespace into the System.Data namespace, alongside the ones defined in the .NET Base Class Libraries.

Once I've compiled this code into an assembly, I can write a client application that uses it. In the client, I need to set a reference to the DAOLib assembly (compiled as DAOLib.dll). I can then write code such as this:

Dim cn1 As New System.Data.DAO.DaoConnection()
Dim cn2 As New System.Data.OleDb.OleDbConnection()
cn1.ConnectionString = "biblio.mdb"
cn2.ConnectionString = _
   "Provider=SQLOLEDB;Database=pubs;"

So now you see how I can work with two of the namespaces contained within the System.Data namespace. I could just as easily use Imports System.Data.DAO to avoid needing to use the fully qualified class name in my code.

Conclusion

Namespaces provide a hierarchical way of organizing class names to avoid "name pollution." That's all they do—they have nothing to do with inheritance and nothing to do with assemblies. They simply define where classes belong in a virtual space of names.

Put like this, namespaces sound simple, and the truth is that, as a concept, they really are. Finding your way around all of the namespaces that exist in the .NET Base Class Libraries is another matter. It seems to me that getting to know namespaces is a lot like getting to know the Windows API—you learn it incrementally as the need arises.

To find out more about Visual Basic Developer and Pinnacle Publishing, visit their website at http://www.pinpub.com/

Note: This is not a Microsoft Corporation website. Microsoft is not responsible for its content.

This article is reproduced from the August 2001 issue of Visual Basic Developer. Copyright 2001, by Pinnacle Publishing, Inc., unless otherwise noted. All rights are reserved. Visual Basic Developer is an independently produced publication of Pinnacle Publishing, Inc. No part of this article may be used or reproduced in any fashion (except in brief quotations used in critical articles and reviews) without prior consent of Pinnacle Publishing, Inc. To contact Pinnacle Publishing, Inc., please call 1-800-788-1900.