The System Namespace
The System namespace sits at the top of the namespace hierarchy. All the rest of the libraries in this chapter and in this book will be descended from the System namespace. (The .NET Framework does include some namespaces that aren't part of the System namespace, but we won't be discussing them in this book.) The most important items contained within the System namespace are the classes that represent the base data types, such as Object, Integer, Long, String, and so on.
In addition to these base data types, there are dozens of classes in the System namespace. These classes cover areas such as data handling (DataSet), garbage collection (GC), and threading (Threading).
The System namespace also contains namespaces that provide the bulk of the .NET Framework functionality. These secondary namespaces are generally grouped into areas of functionality. For example, data access is handled by System.Data, System.Xml, and System.Xml.Serialization, whereas the System.Drawing and System.Windows.Forms namespaces handle user interfaces.
A System.GC (Garbage Collection) Example
As an example of the System namespace, this section takes a look at garbage collection. Garbage collection is one of the important new features you can control when you use the .NET Framework. In COM, instantiated objects are allocated memory automatically. These COM components kept an internal counter of the number of connections being made to them. When this counter drops to zero, the object is supposed to drop out of memory.
In your client code, you can instantiate a COM component (creating an object in memory) and later kill it by setting your object reference to Nothing. As long as you have the only connection to the COM object (the most likely scenario), the object is destroyed immediately.
The problem with using COM reference counting is that it's possible and actually far too easy for one component to maintain a reference to another, while the second maintains a reference back to the first. Because neither component can be destroyed (each has a "live" inward reference), neither object can ever remove itself from memory. This circular reference problem has led to many memory leaks.
Memory management is now handled automatically by the .NET Framework, without reliance on reference counting. The circular reference problem is gone, because the Framework decides when objects are to be released from memory, based on their usage. This means that you do not know exactly when objects will be destroyed, so you can't be sure when the memory is to be cleaned up.
If you want more control, you can force garbage collection to occur by calling the Collect method of the GC class. In the following code snippet, you can see the Collect method being called:
Dim oCust As New Customer() oCust.CompanyName = "Microsoft Corporation" ... oCust = Nothing GC.Collect()
This code instantiates a hypothetical Customer object. It sets the CompanyName property and then might perform other actions on the object. When it's done, the code sets the object reference to Nothing and explicitly calls the Collect method of the GC class. Not calling the Collect method would mean that the object, while no longer referenced, might still be alive in memory. It would be marked for garbage collection but might not be removed until garbage collection is run.
Perhaps you're wondering why you might ever call the garbage collector manually, given that .NET is so good about handling memory for you? Realize that the component, although dereferenced (set to Nothing), may still exist in memory for some time. Not only is it taking up memory, but more importantly, any resources it was accessing may still be held open. For example, database connections and file handles might still be held open until the object is actually dropped from memory. Therefore, you might want to explicitly call the garbage collector and have the object taken out of memory. Of course, a careful programmer would close all open resources before an object is dereferenced.
Working with Namespace Names
The previous example works with the System.GC class, yet it's referred to simply as GC. How is that possible? How can the compiler determine which exact class you're referring to? When referring to members of a namespace (that is, objects provided by a namespace), you must somehow indicate to Visual Basic .NET which exact object you want to use. In general, you must type the entire object name, including its full namespace. For example, to refer to a SqlDataReader object, you would have to write code like this:
Dim dr As New System.Data.SqlClient.SqlDataReader()
If you refer to objects in the same namespace often, you may want to find some way to simply refer to the objects themselves, rather than the entire namespace. To make this possible, VB .NET provides the Imports statement, which you can place at the top of any file. This statement acts much like a file-wide With…End With statement. If, for example, you have placed the statement
at the top of a file, you could modify the previous code example to look like this:
Dim dr As New SqlDataReader()
To make this easier for you, VB .NET projects created in Visual Studio .NET always add implicit Imports statements for you. You can check the list of implicit Imports by right-clicking an open project in the Solution Explorer. Select Imports from the list of common properties in the project's property pages, and you'll see a list of Imports statements that VB .NET automatically handles for you.
In your code, you can only refer to objects that are provided by the assemblies your project references. That is, unless Visual Studio .NET has automatically set a reference to an assembly or you've manually added the reference, you won't be able to use an object. Also, you can only add Imports statements for classes you've referenced. To add a reference to an assembly, use the Project, Add Reference menu item and select the .NET tab.
The GC class provides only shared members. The shared keyword indicates that you don't need to create an instance of the class before using its methods or properties. Many .NET Framework classes use shared members (such as GC.Collect) rather than requiring you to declare a GC variable and create a new instance. Instance properties and methods (such as the Length property of a specific string) are more common.