Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 133 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
133
Dung lượng
3,14 MB
Nội dung
Release methods on the object’s IUnknown interface. However, in this scenario, object A continues to hold a reference to object B, and vice versa, so the internal cleanup logic of these components is not triggered. In addition, problems can occur if the clients do not properly maintain the COM object’s reference count. For example, an object will never be deactivated if a client forgets to call Release when the object is no longer referenced. To avoid this, the unmanaged environment may attempt to take care of updating the reference count for you, but the object’s reference count can be an invalid indicator of whether or not the object is still being used by the application. For example, consider the references that objects A and B hold. The application can invalidate its references to A and B by setting the associated variables equal to Nothing. However, even though objects A and B are no longer referenced by the application, the Visual Basic runtime cannot ensure that the objects are deactivated because A and B still reference each other. Consider the following (Visual Basic 6) code: ' Class: CCircularRef ' Reference to another object. Dim m_objRef As Object Public Sub Initialize(objRef As Object) Set m_objRef = objRef End Sub Private Sub Class_Terminate() Call MsgBox("Terminating.") Set m_objRef = Nothing End Sub The CCircularRef class implements an Initialize method that accepts a reference to another object and saves it as a member variable. Notice that the class does not release any existing reference in the m_objRef variable before assigning a new value. The following code demonstrates how to use this CCircularRef class to create a circular reference: Dim objA As New CCircularRef Dim objB As New CCircularRef Call objA.Initialize(objB) Call objB.Initialize(objA) Set objA = Nothing Set objB = Nothing After creating two instances (objA and objB) of CCircularRef, both of which have a reference count of one, the code then calls the Initialize method on each object by passing it a reference to the other. Now each of the object’s reference counts is equal to two: one held by the application and one held by the other object. Next, explicitly setting objA and objB to Nothing decrements each object’s reference count by one. However, because the reference count for both instances of CCircularRef is still greater than zero, the objects are not released from memory until the application is terminated. The CLR garbage collector solves the problem of circular references because it looks for a reference from the root application or thread to every class, and all classes that do not have such a reference are marked for deletion, regardless of any other references they might still maintain. The CLR’s Garbage Collector The .NET garbage collection mechanism is complex, and the details of its inner workings are beyond the scope of this book, but it is important to understand the principles behind its operation. The GC is responsible for collecting objects that are no longer referenced. It takes a completely different approach from that of the Visual Basic runtime to accomplish this. At certain times, and based on internal rules, a task will run through all the objects looking for those that no longer have any references from the root application thread or one of the worker threads. Those objects may then be terminated; thus, the garbage is collected. As long as all references to an object are either implicitly or explicitly released by the application, the GC will take care of freeing the memory allocated to it. Unlike COM objects, managed objects in .NET are not responsible for maintaining their reference count, and they are not responsible for destroying themselves. Instead, the GC is responsible for cleaning up objects that are no longer referenced by the application. The Memory Management ❘ 223 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 224 ❘ CHAPTER 4 tHE CommoN laNGuaGE RuNtimE GC periodically determines which objects need to be cleaned up by leveraging the information the CLR maintains about the running application. The GC obtains a list of objects that are directly referenced by the application. Then, the GC discovers all the objects that are referenced (both directly and indirectly) by the “root” objects of the application. Once the GC has identified all the referenced objects, it is free to clean up any remaining objects. The GC relies on references from an application to objects; thus, when it locates an object that is unreachable from any of the root objects, it can clean up that object. Any other references to that object will be from other objects that are also unreachable. Thus, the GC automatically cleans up objects that contain circular references. In some environments, such as COM, objects are destroyed in a deterministic fashion. Once the reference count reaches zero, the object destroys itself, which means that you can tell exactly when the object will be terminated. However, with garbage collection, you can’t tell exactly when an object will be destroyed. Just because you eliminate all references to an object doesn’t mean that it will be terminated immediately. It just remains in memory until the garbage collection process gets around to locating and destroying it, a process called nondeterministic finalization. This nondeterministic nature of CLR garbage collection provides a performance benefit. Rather than expend the effort to destroy objects as they are dereferenced, the destruction process can occur when the application is otherwise idle, often decreasing the impact on the user. Of course, if garbage collection must occur when the application is active, then the system may see a slight performance fluctuation as the collection is accomplished. It is possible to explicitly invoke the GC by calling the System.GC.Collect method, but this process takes time, so it is not the sort of behavior to invoke in a typical application. For example, you could call this method each time you set an object variable to Nothing, so that the object would be destroyed almost immediately, but this forces the GC to scan all the objects in your application — a very expensive operation in terms of performance. It’s far better to design applications such that it is acceptable for unused objects to sit in memory for some time before they are terminated. That way, the garbage collector can also run based on its optimal rules, collecting many dereferenced objects at the same time. This means you need to design objects that don’t maintain expensive resources in instance variables. For example, database connections, open files on disk, and large chunks of memory (such as an image) are all examples of expensive resources. If you rely on the destruction of the object to release this type of resource, then the system might be keeping the resource tied up for a lot longer than you expect; in fact, on a lightly utilized Web server, it could literally be days. The first principle is working with object patterns that incorporate cleaning up such pending references before the object is released. Examples of this include calling the close method on an open database connection or file handle. In most cases, it’s possible for applications to create classes that do not risk keeping these handles open. However, certain requirements, even with the best object design, can create a risk that a key resource will not be cleaned up correctly. In such an event, there are two occasions when the object could attempt to perform this cleanup: when the final reference to the object is released and immediately before the GC destroys the object. One option is to implement the IDisposable interface. When implemented, this interface ensures that persistent resources are released. This is the preferred method for releasing resources. The second option is to add a method to your class that the system runs immediately before an object is destroyed. This option is not recommended for several reasons, including the fact that many developers fail to remember that the garbage collector is nondeterministic, meaning that you can’t, for example, reference an SQLConnection object from your custom object’s finalizer. Finally, as part of .NET 2.0, Visual Basic introduced the Using command. The Using command is designed to change the way that you think about object cleanup. Instead of encapsulating your cleanup logic within your object, the Using command creates a window around the code that is referencing an instance of your object. When your application’s execution reaches the end of this window, the system automatically calls the IDIsposable interface for your object to ensure that it is cleaned up correctly. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com The Finalize Method Conceptually, the GC calls an object’s Finalize method immediately before it collects an object that is no longer referenced by the application. Classes can override the Finalize method to perform any necessary cleanup. The basic concept is to create a method that fills the same need as what in other object-oriented languages is referred to as a destructor. Similarly, the Class_Terminate event available in previous versions of Visual Basic does not have a functional equivalent in .NET. Instead, it is possible to create a Finalize method that is recognized by the GC and that prevents a class from being cleaned up until after the finalization method is completed, as shown in the following example: Protected Overrides Sub Finalize() ' clean up code goes here MyBase.Finalize() End Sub Code snippet from ProVB_Finalization\Form1.vb This code uses both Protected scope and the Overrides keyword. Notice that not only does custom cleanup code go here (as indicated by the comment), but this method also calls MyBase.Finalize, which causes any finalization logic in the base class to be executed as well. Any class implementing a custom Finalize method should always call the base finalization class. Be careful, however, not to treat the Finalize method as if it were a destructor. A destructor is based on a deterministic system, whereby the method is called when the object’s last reference is removed. In the GC system, there are key differences in how a finalizer works: Because the GC is optimized to clean up memory only when necessary, there is a delay between the ➤ time when the object is no longer referenced by the application and when the GC collects it. Therefore, the same expensive resources that are released in the Finalize method may stay open longer than they need to be. The GC doesn’t actually run ➤ Finalize methods. When the GC finds a Finalize method, it queues the object up for the finalizer to execute the object’s method. This means that an object is not cleaned up during the current GC pass. Because of how the GC is optimized, this can result in the object remaining in memory for a much longer period. The GC is usually triggered when available memory is running low. As a result, execution of the ➤ object’s Finalize method is likely to incur performance penalties. Therefore, the code in the Finalize method should be as short and quick as possible. There’s no guarantee that a service you require is still available. For example, if the system is ➤ closing and you have a file open, then .NET may have already unloaded the object required to close the file, and thus a Finalize method can’t reference an instance of any other .NET object. All cleanup activities should be placed in the Finalize method, but objects that require timely cleanup should implement a Dispose method that can then be called by the client application just before setting the reference to Nothing: Class DemoDispose Private m_disposed As Boolean = False Public Sub Dispose() If (Not m_disposed) Then ' Call cleanup code in Finalize. Finalize() ' Record that object has been disposed. m_disposed = True ' Finalize does not need to be called. GC.SuppressFinalize(Me) End If End Sub Protected Overrides Sub Finalize() Memory Management ❘ 225 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 226 ❘ CHAPTER 4 tHE CommoN laNGuaGE RuNtimE ' Perform cleanup here End Sub End Class Code snippet from ProVB_Finalization\DemoDispose.vb The DemoDispose class overrides the Finalize method and implements the code to perform any necessary cleanup. This class places the actual cleanup code within the Finalize method. To ensure that the Dispose method only calls Finalize once, the value of the private m_disposed field is checked. Once Finalize has been run, this value is set to True. The class then calls GC.SuppressFinalize to ensure that the GC does not call the Finalize method on this object when the object is collected. If you need to implement a Finalize method, this is the preferred implementation pattern. This example implements all of the object’s cleanup code in the Finalize method to ensure that the object is cleaned up properly before the GC collects it. The Finalize method still serves as a safety net in case the Dispose or Close methods were not called before the GC collects the object. The IDisposable Interface In some cases, the Finalize behavior is not acceptable. For an object that is using an expensive or limited resource, such as a database connection, a file handle, or a system lock, it is best to ensure that the resource is freed as soon as the object is no longer needed. One way to accomplish this is to implement a method to be called by the client code to force the object to clean up and release its resources. This is not a perfect solution, but it is workable. This cleanup method must be called directly by the code using the object or via the use of the Using statement. The Using statement enables you to encapsulate an object’s life span within a limited range, and automate the calling of the IDisposable interface. The .NET Framework provides the IDisposable interface to formalize the declaration of cleanup logic. Be aware that implementing the IDisposable interface also implies that the object has overridden the Finalize method. Because there is no guarantee that the Dispose method will be called, it is critical that Finalize triggers your cleanup code if it was not already executed. Having a custom finalizer ensures that, once released, the garbage collection mechanism will eventually find and terminate the object by running its Finalize method. However, when handled correctly, the IDisposable interface ensures that any cleanup is executed immediately, so resources are not consumed beyond the time they are needed. Note that any class that derives from System.ComponentModel.Component automatically inherits the IDisposable interface. This includes all of the forms and controls used in a Windows Forms UI, as well as various other classes within the .NET Framework. Because this interface is inherited, let’s review a custom implementation of the IDisposable interface based on the Person class defined in the preceding chapters. The first step involves adding a reference to the interface to the top of the class: Public Class Person Implements IDisposable This interface defines two methods, Dispose and Finalize, that need to be implemented in the class. Visual Studio automatically inserts both these methods into your code: #Region " IDisposable Support " Private disposedValue As Boolean ' To detect redundant calls ' IDisposable Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposedValue Then If disposing Then ' TODO: dispose managed state (managed objects). End If ' TODO: free unmanaged resources (unmanaged objects) Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com ' and override Finalize() below. ' TODO: set large fields to null. End If Me.disposedValue = True End Sub ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above ' has code to free unmanaged resources. Protected Overrides Sub Finalize() ' Do not change this code. Put cleanup code in ' Dispose(ByVal disposing As Boolean) above. Dispose(False) MyBase.Finalize() End Sub ' This code added by Visual Basic to correctly implement the disposable pattern. Public Sub Dispose() Implements IDisposable.Dispose ' Do not change this code. Put cleanup code in ' Dispose(ByVal disposing As Boolean) above. Dispose(True) GC.SuppressFinalize(Me) End Sub #End Region Code snippet from ProVB_Finalization\Person.vb Notice the use of the Overridable and Overrides keywords. The automatically inserted code is following a best-practice design pattern for implementation of the IDisposable interface and the Finalize method. The idea is to centralize all cleanup code into a single method that is called by either the Dispose method or the Finalize method as appropriate. Accordingly, you can add the cleanup code as noted by the TODO: comments in the inserted code. As mentioned in Chapter 1, the TODO: keyword is recognized by Visual Studio’s text parser, which triggers an entry in the task list to remind you to complete this code before the project is complete. Because this code frees a managed object (the Hashtable), it appears as shown here: Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposedValue Then If disposing Then ' TODO: dispose managed state (managed objects). End If ' TODO: free unmanaged resources (unmanaged objects) ' and override Finalize() below. ' TODO: set large fields to null. End If Me.disposedValue = True End Sub Code snippet from ProVB_Finalization\Person.vb In this case, we’re using this method to release a reference to the object to which the mPhones variable points. While not strictly necessary, this illustrates how code can release other objects when the Dispose method is called. Generally, it is up to your client code to call this method at the appropriate time to ensure that cleanup occurs. Typically, this should be done as soon as the code is done using the object. This is not always as easy as it might sound. In particular, an object may be referenced by more than one variable, and just because code in one class is dereferencing the object from one variable doesn’t mean that it has been dereferenced by all the other variables. If the Dispose method is called while other references remain, then the object may become unusable and cause errors when invoked via those other references. There is no easy solution to this problem, so careful design is required if you choose to use the IDisposable interface. Memory Management ❘ 227 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 228 ❘ CHAPTER 4 tHE CommoN laNGuaGE RuNtimE Using IDisposable One way to work with the IDisposable interface is to manually insert the calls to the interface implementation everywhere you reference the class. For example, in an application’s Form1 code, you can override the OnLoad event for the form. You can use the custom implementation of this method to create an instance of the Person object. Then you create a custom handler for the form’s OnClosed event, and ensure cleanup by disposing of the Person object. To do this, add the following code to the form: Private Sub Form1_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed CType(mPerson, IDisposable).Dispose() End Sub Code snippet from ProVB_Finalization\Form1.vb The OnClosed method runs as the form is being closed, so it is an appropriate place to do cleanup work. Note that because the Dispose method is part of a secondary interface, use of the CType method to access that specific interface is needed in order to call the method. This solution works fine for patterns where the object implementing IDisposable is used within a form, but it is less useful for other patterns, such as when the object is used as part of a Web service. In fact, even for forms, this pattern is somewhat limited in that it requires the form to define the object when the form is created, as opposed to either having the object created prior to the creation of the form or some other scenario that occurs only on other events within the form. For these situations, .NET 2.0 introduced a new command keyword: Using. The Using keyword is a way to quickly encapsulate the life cycle of an object that implements IDisposable, and ensure that the Dispose method is called correctly: Dim mPerson As New Person() Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Using (mPerson) 'insert custom method calls End Using End Sub End Using Code snippet from ProVB_Finalization\Form1.vb The preceding statements allocate a new instance of the mPerson object. The Using command then instructs the compiler to automatically clean up this object’s instance when the End Using command is executed. The result is a much cleaner way to ensure that the IDisposable interface is called. Faster Memory Allocation for Objects The CLR introduces the concept of a managed heap. Objects are allocated on the managed heap, and the CLR is responsible for controlling access to these objects in a type-safe manner. One of the advantages of the managed heap is that memory allocations on it are very efficient. When unmanaged code (such as Visual Basic 6 or C++) allocates memory on the unmanaged heap, it typically scans through some sort of data structure in search of a free chunk of memory that is large enough to accommodate the allocation. The managed heap maintains a reference to the end of the most recent heap allocation. When a new object needs to be created on the heap, the CLR allocates memory on top of memory that has previously been allocated, and then increments the reference to the end of heap allocations accordingly. Figure 4-4 illustrates a simplification of what takes place in the managed heap for .NET: ➤ State 1 — A compressed memory heap with a reference to the endpoint on the heap. ➤ State 2 — Object B, although no longer referenced, remains in its current memory location. The memory has not been freed and does not alter the allocation of memory or other objects on the heap. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com ➤ State 3 — Even though there is now a gap between the memory allocated for object A and object C, the memory allocation for object D still occurs on the top of the heap. The unused fragment of memory on the managed heap is ignored at allocation time. ➤ State 4 — After one or more allocations, before there is an allocation failure, the garbage collector runs. It reclaims the memory that was allocated to object B and repositions the remaining valid objects. This compresses the active objects to the bottom of the heap, creating more space for additional object allocations (refer to Figure 4-4). Object A Reference to top of heap allocations Object B Object C Object A State 1: Objects A, B, and C are allocated on the heap State 2: Object B is no longer referenced by the application Not Referenced Object C Reference to top of heap allocations Object A Reference to top of heap allocations Not Referenced Object C Object D Object A State 3: Object D is allocated on the heap State 4: The GC executes, memory from B is reclaimed, and the heap is compressed Object C Object D Reference to top of heap allocations FIGURE 44 This is where the power of the GC really shines. Before the CLR is unable to allocate memory on the managed heap, the GC is invoked. The GC not only collects objects that are no longer referenced by the application, but also has a second task: compacting the heap. This is important because if the GC only cleaned up objects, then the heap would become progressively more fragmented. When heap memory becomes fragmented, you can wind up with the common problem of having a memory allocation fail — not because there isn’t enough free memory, but because there isn’t enough free memory in a contiguous section of memory. Thus, not only does the GC reclaim the memory associated with objects that are no longer referenced, it also compacts the remaining objects. The GC effectively squeezes out all of the spaces between the remaining objects, freeing up a large section of managed heap for new object allocations. Garbage Collector Optimizations The GC uses a concept known as generations, the primary purpose of which is to improve its performance. The theory behind generations is that objects that have been recently created tend to have a higher probability of being garbage-collected than objects that have existed on the system for a longer time. To understand generations, consider the analogy of a mall parking lot where cars represent objects created by the CLR. People have different shopping patterns when they visit the mall. Some people spend a good portion of their day in the mall, and others stop only long enough to pick up an item or two. Applying Memory Management ❘ 229 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 230 ❘ CHAPTER 4 tHE CommoN laNGuaGE RuNtimE the theory of generations to trying to find an empty parking space for a car yields a scenario in which the highest probability of finding a parking space is a function of where other cars have recently parked. In other words, a space that was occupied recently is more likely to be held by someone who just needed to quickly pick up an item or two. The longer a car has been parked, the higher the probability that its owner is an all-day shopper and the lower the probability that the parking space will be freed up anytime soon. Generations provide a means for the GC to identify recently created objects versus long-lived objects. An object’s generation is basically a counter that indicates how many times it has successfully avoided garbage collection. An object’s generation counter starts at zero and can have a maximum value of two, after which the object’s generation remains at this value regardless of how many times it is checked for collection. You can put this to the test with a simple Visual Basic application. From the File menu, select either File ➪ New ➪ Project, or, if you have an open solution, File ➪ Add ➪ New Project. This opens the Add New Project dialog. Select a console application, provide a name and directory for your new project, and click OK. After you create your new project, you will have a code module that looks similar to the code that follows. Within the Main module, add the highlighted code. In Solution Explorer, right-click your second project (if the new project was added to an existing project) and select the Set as StartUp Project option so that when you run your solution, your new project is automatically started. Module Module1 Sub Main() Dim myObject As Object = New Object() Dim i As Integer For i = 0 To 3 Console.WriteLine(String.Format("Generation = {0}", _ GC.GetGeneration(myObject))) GC.Collect() GC.WaitForPendingFinalizers() Next i Console.Read() End Sub End Module Code snippet from ProVB_C04_Memory\Module1.vb Regardless of the project you use, this code sends its output to the .NET console. For a Windows application, this console defaults to the Visual Studio Output window. When you run this code, it creates an instance of an object and then iterates through a loop four times. For each loop, it displays the current generation count of myObject and then calls the GC. The GC.WaitForPendingFinalizers method blocks execution until the garbage collection has been completed. As shown in Figure 4-5, each time the GC was run, the generation counter was incremented for myObject, up to a maximum of 2. FIGURE 45 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Each time the GC is run, the managed heap is compacted, and the reference to the end of the most recent memory allocation is updated. After compaction, objects of the same generation are grouped together. Generation-2 objects are grouped at the bottom of the managed heap, and generation-1 objects are grouped next. New generation-0 objects are placed on top of the existing allocations, so they are grouped together as well. This is significant because recently allocated objects have a higher probability of having shorter lives. Because objects on the managed heap are ordered according to generations, the GC can opt to collect newer objects. Running the GC over a limited portion of the heap is quicker than running it over the entire managed heap. It’s also possible to invoke the GC with an overloaded version of the Collect method that accepts a generation number. The GC will then collect all objects no longer referenced by the application that belong to the specified (or younger) generation. The version of the Collect method that accepts no parameters collects objects that belong to all generations. Another hidden GC optimization results from the fact that a reference to an object may implicitly go out of scope; therefore, it can be collected by the GC. It is difficult to illustrate how the optimization occurs only if there are no additional references to the object and the object does not have a finalizer. However, if an object is declared and used at the top of a module and not referenced again in a method, then in the release mode, the metadata will indicate that the variable is not referenced in the later portion of the code. Once the last reference to the object is made, its logical scope ends; and if the garbage collector runs, the memory for that object, which will no longer be referenced, can be reclaimed before it has gone out of its physical scope. NAMESPACES Even if you did not realize it, you have been using namespaces since the beginning of this book. For example, System, System.Diagnostics, and System.Windows.Forms are all namespaces contained within the .NET Framework. Namespaces are an easy concept to understand, but this chapter puts the ideas behind them on a firm footing — and clears up any misconceptions you might have about how they are used and organized. If you are familiar with COM, you will find that the concept of namespaces is the logical extension of programmatic identifier (ProgID) values. For example, the functionality of Visual Basic 6’s FileSystemObject is now mostly encompassed in .NET’s System.IO namespace, though this is not a one-to-one mapping. However, namespaces reflect more than a change in name; they represent the logical extension of the COM naming structure, expanding its ease of use and extensibility. In addition to the traditional System and Microsoft namespaces (for example, used in things such as Microsoft’s Web Services Enhancements), the .NET Framework 3.5 included a way to access some tough-to- find namespaces using the My namespace. The My namespace is a powerful way of “speed-dialing” specific functionalities in the base. What Is a Namespace? Namespaces are a way of organizing the vast number of classes, structures, enumerations, delegates, and interfaces that the .NET Framework class library provides. They are a hierarchically structured index into a class library, which is available to all of the .NET languages, not only the Visual Basic 2010 language (with the exception of the My namespace). The namespaces, or object references, are typically organized by function. For example, the System.IO namespace contains classes, structures, and interfaces for working with input/output streams and files. The classes in this namespace do not necessarily inherit from the same base classes (apart from Object, of course). A namespace is a combination of a naming convention and an assembly, which organizes collections of objects and prevents ambiguity about object references. A namespace can be, and often is, implemented across several physical assemblies, but from the reference side, it is the namespace that ties these assemblies together. A namespace consists of not only classes, but also other (child) namespaces. For example, IO is a child namespace of the System namespace. Namespaces ❘ 231 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 232 ❘ CHAPTER 4 tHE CommoN laNGuaGE RuNtimE Namespaces provide identification beyond the component name. With a namespace, it is possible to use a more meaningful title (for example, System) followed by a grouping (for example, Text) to group together a collection of classes that contain similar functions. For example, the System.Text namespace contains a powerful class called StringBuilder. To reference this class, you can use the fully qualified namespace reference of System.Text.StringBuilder, as shown here: Dim sb As New System.Text.StringBuilder() The structure of a namespace is not a reflection of the physical inheritance of classes that make up the namespace. For example, the System.Text namespace contains another child namespace called RegularExpressions. This namespace contains several classes, but they do not inherit or otherwise reference the classes that make up the System.Text namespace. Figure 4-6 shows how the System namespace contains the Text child namespace, which also has a child namespace, called RegularExpressions. Both of these child namespaces, Text and RegularExpressions, contain a number of objects in the inheritance model for these classes, as shown in the figure. System.Text System.Text.RegularExpressions Capture Group Encoding CaptureCollection GroupCollection MatchCollection RegEx RegExCompilationInfo Object StringBuilder UTF8Encoding UTF7Encoding ASCIIEncoding Encoding Encoder Decoder UnicodeEncoding FIGURE 46 As shown in Figure 4-6, while some of the classes in each namespace do inherit from each other, and while all of the classes eventually inherit from the generic Object, the classes in System.Text .RegularExpressions do not inherit from the classes in System.Text. To emphasize the usefulness of namespaces, we can draw another good example from Figure 4-6. If you make a reference to System.Drawing.Imaging.Encoder in your application, then you are making a reference to a completely different Encoder class than the namespace shown in Figure 4-6 — System.Text.Encoder. Being able to clearly identify classes that have the same name but very different functions, and disambiguate them, is yet another advantage of namespaces. If you are an experienced COM developer, you may note that unlike a ProgID, which reflects a one-level relationship between the project assembly and the class, a single namespace can use child namespaces to extend the meaningful description of a class. The System namespace, imported by default as part of every project created with Visual Studio, contains not only the default Object class, but also many other classes that are used as the basis for every .NET language. What if a class you need isn’t available in your project? The problem may be with the references in your project. For example, by default, the System.DirectoryServices namespace, used to get programmatic access to the Active Directory objects, is not part of your project’s assembly. Using it requires adding a Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... Microsoft.VisualBasic, and the accompanying Microsoft.VisualBasic.dll Every Visual Basic 2010 project includes the namespace Microsoft.VisualBasic This namespace is part of the Visual Studio project templates for Visual Basic 2010 and is, in short, what makes Visual Basic 2010 different from C# or any other NET language The implicit inclusion of this namespace is the reason why you can call IsDBNull and. .. colors and 3- D shapes With the introduction of XAML and the integration of XAML with Visual Basic for things like WPF, Silverlight, WF, and over time other technologies, you—as a Visual Basic developer—will be doing more and more declarative programming In most cases, once you understand how XAML differs from and works with imperative languages like Visual Basic, you’ll fi nd it easier to master XAML; and. .. methods of Visual Basic 2010 directly The only difference in the default namespaces included with Visual Basic 2010 and C# Windows Forms Application projects is that the former use Microsoft.VisualBasic and the latter use Microsoft.CSharp To see all of the namespaces that are imported automatically, such as the Microsoft.VisualBasic namespace, right-click the project name in the Solution Explorer and select... the Visual Studio 2010 IDE You can find it by selecting View ➪ Object Browser if you are using Visual Studio 2010, 2005, or 20 03, or View ➪ Other Windows ➪ Object Browser if you are using Visual Studio 2002 The Visual Studio 2010 Object Browser is shown in Figure 4- 12 The Object Browser displays each of the referenced assemblies and enables you to drill down into the various namespaces Figure 4- 12... project’s Properties window in Visual Studio Select the References tab from the left pane and you will see the reference Microsoft.VisualBasic at the top of the list (see Figure 4- 11) Figure 4- 11 When looking at the project’s global list of imports in the text area at the bottom of the page, you can see that in addition to the Microsoft.VisualBasic namespace, the System.Collections and System Diagnostics namespaces... System.Data.dll Let’s create a sample project so you can examine the role that namespaces play within it Using Visual Studio 2010, create a new Visual Basic Windows Forms Application project called Namespace_Sampler The Microsoft.VisualBasic.Compatibility.VB6 library is not part of Visual Basic 2010 projects by default To gain access to the classes that this namespace provides, you need to add it to your... type="System.Diagnostics.EventLogTraceListener" initializeData="EvjenEventWriter" /> ... This is because the single Microsoft.VisualBasic Compatibility.VB6 namespace is actually implemented in two separate assemblies If you also make a reference to the Microsoft.VisualBasic.Compatibility namespace, as well as the Microsoft VisualBasic.Compatibility.Data namespace, you will see (through the Object Browser found in Visual Studio) that the Microsoft.VisualBasic.Compatibility.VB6 namespace is... 2 54 ❘ Chapter 5 Declarative Programming with Visual Basic to a single technology At the same time, the format should feel somewhat familiar to those who know HTML and/ or XML and XSLT The implementation code to interpret and act on XAML declarations, becomes plumbing that a declarative programmer leaves to Microsoft (or some component implementation vendor) Declarative Programming and Visual Basic. .. using the File menu in Visual Studio 2010 and select the option to create a new project Navigate to the new Visual Basic Window section of the New Project dialog, as shown in Figure 5-1 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 256 ❘ Chapter 5 Declarative Programming with Visual Basic Figure 5-1 For the purpose of this chapter you can create a NET 4 application called . Microsoft.VisualBasic, and the accompanying Microsoft.VisualBasic.dll. Every Visual Basic 2010 project includes the namespace Microsoft.VisualBasic. This namespace is part of the Visual Studio. Using Visual Studio 2010, create a new Visual Basic Windows Forms Application project called Namespace_Sampler. The Microsoft.VisualBasic.Compatibility.VB6 library is not part of Visual Basic 2010. click OK. FIGURE 4 7 Namespaces ❘ 233 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 2 34 ❘ CHAPTER 4 tHE CommoN laNGuaGE RuNtimE The example in Figure 4- 7 is importing