A V I S U A L B A S I C . N E T
C R A S H C O U R S E
Visual Basic (VB), for all intensive purposes, has arrived, and it’s just as powerful and flexible as any other .NET language, although this may well be due more to the strength of the .NET Framework than to Visual Basic as a programming language. All versions of VB prior to Visual Basic .NET (let’s refer to these versions as “classic” VB) were criticized as being non-object oriented programming languages not worthy of enterprise level or mission critical applications. However, while earlier versions lacked true full inheritance, they have been widely used to deliver mission critical applications successfully.
The fact is, a well-written Visual C++ application will nearly always out perform a Visual Basic application. But Visual Basic, while lacking in some flexibility and power, is easier to implement than Visual C++. Furthermore, because VB lacks flexibility and power, developers are less likely to create multithread problems or memory leaks at the cost of performance and stability.
This chapter provides an overview of many new Visual Basic .NET features and concepts. (For a detailed language reference, see the MSDN library online or The Book of VB .NET, .NET Insight for VB Developers.)
What’s New in Visual Basic .NET?
The number of language enhancements in Visual Basic. NET nearly justifies the creation of a new language. Let’s look at a few of the more visible changes.
Forcing the explicit declaration of all variables reduces potential bugs. Classic
VB required an Option Explicit statement in the declaration section of code if
we wanted the Visual Basic compiler to enforce variable declaration which held
the potential for problems because variables were often misspelled. When using
Option Explicit, an entirely new variable is created if not already declared.
Unlike classic VB, Visual Basic .NET implements Option Explicit by default, preventing
the accidental creation of new variables and protecting the use of
Option Strict is similar to Option Explicit in that it tells the compiler to require
a variable declaration and requires all data conversions to be explicit. In classic
Visual Basic, implicit conversions are not possible when Option Strict is on.
(This setting is off by default.)
Option Compare, as you might guess, determines how strings will be evaluated.
The two possible parameter values are binary and text. Binary compares the literal
binary values of the two values being compared. A binary compare would
mean the upper- and lower- case values cannot be equal, in effect enforcing
case-sensitive compares. Text allows the evaluation of two variables to be case –
insensitive. Your application requirements will determine which Option Compare
option you will use.
Option Base is a retired option of classic Visual Basic that allowed developers to
determine whether or not arrays will be 0 or 1 based. Visual Basic .NET no
longer recognizes this option and sets all arrays to base 0.
Variables in .NET come in two flavors: value types and reference types. All primitive
data types with the exception of the string data type are value type variables.
All classes including the string data type are reference types.
The most significant difference between the types is in how they are stored
in memory. Value types are stored in a stack (which requires a smaller memory
footprint), while reference types are stored in a heap.
Boxing occurs when a value type is converted to a reference type and recreated
on the heap. Boxing should be used sparingly as the ability to move values from
the stack to the heap is performance intensive.
The most common occurrence of boxing is when a value type variable is
passed to a procedure that accepts the System.Object data type. System.Object is
the equivalent of the classic Visual Basic variant data type.
The ReDim statement, available in classic Visual Basic, is still available in Visual
Basic .NET. Classic V isual Basic no t only allowed developers to rediminish an
array, but also initialize the array. Visual Basic .NET allows the use of ReDim to
rediminish an array but not to initialize an array.
The StringBuilder class is an impressive class optimizing string manipulation.
You’ll better understand its advantages once you understand how string manipulation
has historically worked.
Classic Visual Basic hid the actual implementation code supporting functions
available in the Visual Basic library, and string manipulation was no exception.
One common string function is the concatenation of two strings.
Unfortunately, Visual Basic doesn’t simply add the two strings together; instead,
the windows system determines the space required for the new string, allocates
memory, and places the new concatenated value into the newly allocated memory.
The StringBuilder class is implemented as an array of characters. This
allows it to implement methods to manipulate what appears to be a string without
the overhead incurred by an actual string. The Insert method of the
StringBuilder class is used to add to the character array in a way that is much
more efficient than classic string manipulation, increasing performance of many
common programming scenarios. (You’ll find the StringBuilder class in the
Using the StringBuilder
This example will show you how to use the StringBuilder class and will compare
its performance against the performance of classic Visual Basic string concatenation.
To begin, follow these steps:
- Create a windows project and build a window that looks the same as Figure 7-1, using the parameters in Table 7-1.
- Add the following code segment to the click event of the btnString button.
Dim dateStart As Date Dim strString As String Dim i As Integer dateStart = DateAndTime.TimeOfDay For i = 1 To 15000 strString = strString & "string value " Next i lblStringDisplay.Text = DateAndTime.DateDiff(DateInterval.Second, _ dateStart, DateAndTime.TimeOfDay) & " Seconds"
- Add the following code segment to the click event of the btnStringBuilder button.
Dim dateStart As Date Dim objString As New System.Text.StringBuilder() Dim i As Integer dateStart = DateAndTime.TimeOfDay For i = 1 To 15000 objString = objString.Append("string value ") Next i lblStringBuilderDisplay.Text = DateAndTime.DateDiff( _ DateInterval.Second, dateStart, _ DateAndTime.TimeOfDay) & " Seconds"
- Now run the example and press each button. You will see a significant difference between the performances of the two methods of string concatenation.
Figure 7-1: Using the StringBuilder class.
Table 7-1: Parameters for the StringBuilder Class
Control Property Value
Button Name btnString
Text strString = strString & “string value”
Button Name BtnStringBuilder
Text objStringBuilder = objStringBuilder.Append(“string value”)
Label Name lblStringDisplay
Label Name lblStringBuildingDisplay
Label Text The first button concatinates strings the classic VB way while the
second button used the StringBuilder class. Each will loop through
each concatination 15000 times.
Previously, strings were built by simply adding one onto the end of another. This only
seems to be what is happening. What is actually occurring is something different. When
adding one string to another, you begin with the original string in memory, then a new
string is allocated in memory for the string being added. Next, a new string representing
the new concatenated string is created and the new string placed into it, and finally, the
original string and the added string are de-allocated, leaving only the newly
concatenated string in memory.
As you might imagine, this is a very inefficient process for simply adding
two string values together. The StringBuilder class is a collection of characters.
The StringBuilder character collection can allow values to be added and
removed without the need to re-allocate and de-allocate memory blocks. As you
will see, the performance difference is significant.
Classic Visual Basic allowed developers to create their own data types called
User Defined Data Types or UDTs, which were implemented using the Type
keyword. Visual Basic .NET has retired the Type keyword and replaced it with
the keyword Structure, like so:
Public Structure Person Dim strFirstName as String Dim strLastName as String End Struct
All variables have a predefined scope that is assigned during initialization. Listed
below are a few of the most common scope declarations and their definitions.
- Private scope: Defines a variables scope as restricted to the current method.
A variable defined as having private scope is referred to as a member variable
and is commonly prefixed with an “m”.
- Public scope: Allows the parent class, or calling class, access to the data held
by a public variable or method.
- Friend scope: Similar to public scope as far as all code within a project is
concerned. The difference between the public scope and friend scope is that
variables or methods that are defined with the friend scope cannot be
accessed by a parent class outside of the project.
- Protected scope: A new scope declaration that allows access to classes that
inherit from the variables class.
The #Region directive allows you to organize your code into collapsible blocks
which help to make the code window easier to work with by displaying only
those functions you are working with. Each region can be defined with a name
helping each region to be more easily identifiable, as shown here
#Region "MyRegion" 'some code #End Region
When you are done writing “some code,” you can collapse the region and
begin working on the next segment of code.
Visual Basic .NET implements Windows Forms as classes that inherit windows
functionality from the Form class found in the System.Windows.Forms namespace.
Developing Win32 applications in Visual Basic .NET is still very similar to
classic Visual Basic windows development in that windows controls can be
dragged and dropped onto the form designer. The difference is that none of
the implementation code is hidden.
For example, here’s the implementation code for the Windows Form discussed
in the previous example of the StringBuilder class. While this type of
code must be implemented in classic Visual Basic forms, it is hidden. As you can
see, the code is no longer hidden; however, I would strongly recommend leaving
this code alone unless you really know what you are doing and have a specific
need to fill. Take a look at t he code below and notice that the entire form is
actually a class that inherits the System.Windows.Forms.form class. As mentioned
earlier in this book, everything in .NET is a class. There are no exceptions.
Public Class Form1 Inherits System.Windows.Forms.Form #Region " Windows Form Designer generated code " Public Sub New() MyBase.New() 'This call is required by the Windows Form Designer. InitializeComponent() 'Add any initialization after the InitializeComponent() call End Sub 'Form overrides dispose to clean up the component list. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub 'Required by the Windows Form Designer Private components As System.ComponentModel.IContainer 'NOTE: The following procedure is required by the Windows Form Designer ' End Sub #End Region End Class
The implementation code for all the controls on the form were stored in the
“Windows Form Designer generated code” region. (This information has been
removed so you won’t be distracted from the Windows Form’s own implementation.)
While the Visual Basic compiler used a file’s extension to determine what type of
project file it was, Visual Basic .NET implements all code through classes. All
Visual Studio .NET needs to know is the language the file is written in.
Project groups in Visual Studio have proved to be a powerful tool for managing,
building, and debugging multiple project solutions. Visual Studio .NET
replaces the Group Project with a Project Solution, which is one or more projects
and the supporting files. Because solutions actually contain projects and
items, they are often referred to as Solution Containers. And, because projects
also contain files, it should come as no surprise that projects are referred to as
Solutions and project files each have their own extensions so that Visual
Studio .NET knows what kind of container they are:
- .sln: The file extension of a solution file which maintains all solution
- .suo: The file extension of all Solution User Options files which maintains
all of the user’s preference information for the solution.
- .vbproj: The file extension of all Visual Basic project files.
- .vb and .cs: The file extensions of Visual Basic .NET and C# files,
respectively. This is a significant improvement from previous versions of
Visual Studio when forms, classes, and other components were given
component specific file which offered no clue as to the language used to
build the file. Project items built using a specific language will always have
that language’s file extension, thus allowing Visual Studio .NET to know
which compiler it must use. (For additional information on file extensions
of project items, refer to the MSDN article entitled, “File Types and File
Extensions in Visual Basic and Visual C#”.)
One of the more interesting Windows and Web Form improvements is the ability
to alert the user of exceptions without interrupting them until they press a
button that performs validation, providing better overall user experience. The
ErrorProvider component is a non-visual component that allows you to perform
data validation on form controls. If a data violation occurs, you can set a message
to be displayed as a tool tip near the offending control.
Ideally, you should implement data validation, a type of business rule enforcement, at the lowest common layer. The most ideal place to do so is at the database level because this is the only application layer that cannot be bypassed. Furthermore, rules enforced here are not duplicated as they would be if you implemented business rules in the presentation layer. For example, if a name can be equal to or less than 20 characters and the rule is implemented in the presentation layer, then every form that supports the use of the name must implement the same rule. If the rule is changed, it must be changed in every form that uses the name. This is both sloppy and error prone.
Current technology does not lend itself to this level of data validation very easily; however, over time Microsoft will devise better validation schemes and developers will build custom solutions. The challenge is to provide solid data validation without compromising user experience. To implement data validation in the presentation layer means that we are duplicating business rule enforcement because the same rules are surely implemented in the database as well. Of course the risk is that when the database schema changes, we may miss making the same changes in the presentation layer.
If all business rules are implemented in the Component layer, it is possible
to bypass the rules by ignoring the Component layer or building another one
that does not implement the rule. In such a case, you have the potential of corrupting
data that will be more expensive to repair then it would have cost to
devise a sound business rules enforcement schema.
The XML Schema is excellent place to begin looking for sound business rule
implementation. By pulling the database schema from the database and persisting it in
memory, you can leverage XML Schema to enforce data types and constraints. Also, when
building your web page dynamically you can enforce these data specific rules through the
ErrorProvider. In this case, you are implementing rules at the business level layer, which
were defined in the database at design time; the violation can be made known through the
ErrorProvider at the presentation layer. This is the ideal way to enforce data specific
business rules; all other programmatic business rules should be implemented in the
business level layer. Never enforce business rules in the presentation layer.
Namespaces make it easy to organize classes, functions, data types, and structures
into a hierarchy. Namespaces allow you to quickly access classes and methods
buried in the .NET Framework Class Library or any other application that
provides a namespace. The .NET Framework Class Library provides hundreds of
classes and thousands of functions as well as data types and structures.
Use the Imports statement to import a namespace for easy access to its
classes and methods. Once imported it is no longer necessary to use a fully qualified
path to the desired class or method. For example:
Imports system.text ' Give access to the StringBuilder class
Table 7-2 lists the namespaces that are used most commonly and their general
Table 7-2: Commonly Used Namespaces
Microsoft.VisualBasic Contains the Visual Basic .NET runtime, classes, and methods used for compiling Visual Basic code.
Microsoft.VSA Provides a host of scripting functionality, allowing you to give
Microsoft.Win32 Provides access to the Windows Registry and the ability to
System Provides basic classes and methods commonly used by all .NET
System.Collection Provides interfaces and classes used for creating a variety of
Collection types are
System.ComponentModel Provides classes and interfaces for runtime and design time
The Container interface allows the Visual Studio .NET
System.Data Provides classes and interfaces to support data access including
System.Diagnostics Provides classes, allowing access to
System.DirectoryServices Provides the ability to search and interact with Active Directory
System.EnterpriseService Provides the ability to employ COM+ functionality for building enterprise applications.
System.Globalization Provides classes supporting multiple languages and cultures
System.IO Provides read and write access to data streams and files.
System.Management Provides access to information provided by WMI (Windows
System.Messaging Provides classes for managing Message Queues.
System.Net Provides classes for commonly used network protocols.
System.Reflection Provides classes for access to component metadata stored in an
System.Runtime.Remoting Provides classes designed for building distributed applications similar to classic DCOM (Distributed Component Object Model).
System.Runtime.Serialization Provides classes designed to serialize objects into a sequence of bits for storage or transfer to another system.
System.Security Implements the CLR’s (Common Language Runtime) security
System.ServiceProcess Provides classes required for building Windows Services.
System.Text Provides classes for manipulating string data. Most notable is the
System.Tread Provides classes for building multi-threaded applications.
System.Timer Provides classes for implementing non-visual timed events
System.Web Provides classes and additional subordinate namespaces
System.Windows.Forms Provides classes required for developing windows form
System.XML Provides classes for manipulating and using XML.
This ends the first of three parts of a sample chapter from The Book of Visual Studio .NET, ISBN 1-886411-69-7 from No Starch Press
# # #