BUY THIS BOOK

Safari Books Online

What is this?

Looking to Reprint this content?


Programming Visual Basic .NET
Programming Visual Basic .NET

By Dave Grundgeiger

Cover | Table of Contents


Table of Contents

Chapter 1: Introduction
With its release for the .NET platform, the Visual Basic language has undergone dramatic changes. For example:
  • The language itself is now fully object-oriented.
  • Applications and components written in Visual Basic .NET have full access to the .NET Framework, an extensive class library that provides system and application services.
  • All applications developed using Visual Basic .NET run within a managed runtime environment, the .NET common language runtime.
In this introduction, I briefly discuss these changes and other changes before showing you three very simple, but complete, Visual Basic .NET applications.
The .NET Framework encompasses the following:
  • A new way to expose operating system and other APIs. For years, the set of Windows functionality that was available to developers and the way that functionality was invoked were dependent on the language environment being used. For example, the Windows operating system provides the ability to create windows (obviously). Yet, the way this feature was invoked from a C++ program was dramatically different from the way it was invoked from a Visual Basic program. With .NET, the way that operating system services are invoked is uniform across all languages (including code embedded in ASP.NET pages).
    This portion of .NET is commonly referred to as the .NET Framework class library.
  • A new infrastructure for managing application execution. To provide a number of sophisticated new operating-system services—including code-level security, cross-language class inheritance, cross-language type compatibility, and hardware and operating-system independence, among others—Microsoft developed a new runtime environment known as the Common Language Runtime (CLR). The CLR includes the Common Type System (CTS) for cross-language type compatibility and the Common Language Specification (CLS) for ensuring that third-party libraries can be used from all .NET-enabled languages.
    To support hardware and operating-system independence, Microsoft developed the Microsoft Intermediate Language (MSIL, or just IL). IL is a CPU-independent machine language-style instruction set into which .NET Framework programs are compiled. IL programs are compiled to the actual machine language on the target platform prior to execution (known as
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What Is the Microsoft .NET Framework?
The .NET Framework encompasses the following:
  • A new way to expose operating system and other APIs. For years, the set of Windows functionality that was available to developers and the way that functionality was invoked were dependent on the language environment being used. For example, the Windows operating system provides the ability to create windows (obviously). Yet, the way this feature was invoked from a C++ program was dramatically different from the way it was invoked from a Visual Basic program. With .NET, the way that operating system services are invoked is uniform across all languages (including code embedded in ASP.NET pages).
    This portion of .NET is commonly referred to as the .NET Framework class library.
  • A new infrastructure for managing application execution. To provide a number of sophisticated new operating-system services—including code-level security, cross-language class inheritance, cross-language type compatibility, and hardware and operating-system independence, among others—Microsoft developed a new runtime environment known as the Common Language Runtime (CLR). The CLR includes the Common Type System (CTS) for cross-language type compatibility and the Common Language Specification (CLS) for ensuring that third-party libraries can be used from all .NET-enabled languages.
    To support hardware and operating-system independence, Microsoft developed the Microsoft Intermediate Language (MSIL, or just IL). IL is a CPU-independent machine language-style instruction set into which .NET Framework programs are compiled. IL programs are compiled to the actual machine language on the target platform prior to execution (known as just-in-time , or JIT, compiling). IL is never interpreted.
  • A new web server paradigm. To support high-capacity web sites, Microsoft has replaced its Active Server Pages (ASP) technology with ASP.NET. While developers who are used to classic ASP will find ASP.NET familiar on the surface, the underlying engine is different, and far more features are supported. One difference, already mentioned in this chapter, is that ASP.NET web page code is now compiled rather than interpreted, greatly increasing execution speed.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What Is Visual Basic .NET?
Visual Basic .NET is the next generation of Visual Basic, but it is also a significant departure from previous generations. Experienced Visual Basic 6 developers will feel comfortable with Visual Basic .NET code and will recognize most of its constructs. However, Microsoft has made some changes to make Visual Basic .NET a better language and an equal player in the .NET world. These include such additions as a Class keyword for defining classes and an Inherits keyword for object inheritance, among others. Visual Basic 6 code can't be compiled by the Visual Basic .NET compiler without significant modification. The good news is that Microsoft has provided a migration tool to handle the task (mostly, anyway). Code migration is explained in Appendix A. The Visual Basic .NET language itself is detailed in Chapter 2.
Over the last several months I have spent almost all of my time playing with .NET and writing Visual Basic .NET programs. As a user of Visual Basic since Version 4, I can tell you that I am pleased with this new technology and with the changes that have been made to Visual Basic. In my opinion, Microsoft has done it right.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
An Example Visual Basic .NET Program
The first program to write is the same for all languages: Print the words hello, world
—Brian W. Kernighan and Dennis M. Ritchie, The C Programming Language
It has become a tradition for programming books to begin with a hello, world example. The idea is that entering and running a program—any program—may be the biggest hurdle faced by experienced programmers approaching a new platform or language. Without overcoming this hurdle, nothing else can follow. This chapter contains three such examples: one that creates a console application, one that creates a GUI application, and one that creates a browser-based application. Each example stands alone and can be run as is. The console and GUI applications can both be compiled from the command line (yes, Visual Basic .NET has a command-line compiler!). The browser-based application requires a computer running Internet Information Server (IIS).
This is the world's favorite programming example, translated to Visual Basic .NET:
Imports System

Public Module Hello
   Public Sub Main(  )
      Console.WriteLine("hello, world")
   End Sub
End Module
This version of hello, world is a console application -- it displays its output in a Windows command-prompt window. To compile this program, enter it using any text editor, such as Windows's Notepad, save it in a file whose name ends with .vb, such as Hello.vb, and compile it from the Windows command line with this command:
vbc Hello.vb
The command vbc invokes the Visual Basic .NET command-line compiler, which ships with the .NET Framework SDK, and instructs it to compile the file named in the command-line argument. Compiling Hello.vb generates the file Hello.exe. After compiling, type Hello at the command line to run your program. Figure 1-1 shows the results of compiling and running this program.
Figure 1-1: Compiling and running hello, world
If you're accustomed to programming in Visual Basic 6, you can see even from this little program that Visual Basic has changed dramatically. Here's a breakdown of what's happening in this code.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: The Visual Basic .NET Language
This chapter discusses the syntax of the Visual Basic .NET language, including basic concepts such as variables, operators, statements, classes, etc. Some material that you'd expect to find in this chapter will seem to be missing. For example, mathematical functions, file I/O, and form declarations are all very much a part of developing Visual Basic .NET applications, yet they are not introduced in this chapter because they are not intrinsic to the Visual Basic .NET language. They are provided by the .NET Framework and will be discussed in subsequent chapters. Additionally, Visual Basic .NET functions that exist merely for backward compatibility with Visual Basic 6 are not documented in this chapter.
Visual Basic .NET source code is saved in files with a .vb extension. The exception to this rule is when Visual Basic .NET code is embedded in ASP.NET web page files. Such files have an .aspx extension.
Source files are plain-text files that can be created and edited with any text editor, including our old friend, Notepad. Source code can be broken into as many or as few files as desired. When you use Visual Studio .NET, source files are listed in the Solution Explorer window, and all source is included from these files when the solution is built. When you are compiling from the command line, all source files must appear as command-line arguments to the compile command. The location of declarations within source files is unimportant. As long as all referenced declarations appear somewhere in a source file being compiled, they will be found.
Unlike previous versions of Visual Basic, no special file extensions are used to indicate various language constructs (e.g., .cls for classes, .frm for forms, etc.). Syntax has been added to the language to differentiate various constructs. In addition, the pseudolanguage for specifying the graphical layout of forms has been removed. Form layout is specified by setting properties of form objects explicitly within code. Either this code can be written manually, or the WYSIWYG form designer in Visual Studio .NET can write it.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Source Files
Visual Basic .NET source code is saved in files with a .vb extension. The exception to this rule is when Visual Basic .NET code is embedded in ASP.NET web page files. Such files have an .aspx extension.
Source files are plain-text files that can be created and edited with any text editor, including our old friend, Notepad. Source code can be broken into as many or as few files as desired. When you use Visual Studio .NET, source files are listed in the Solution Explorer window, and all source is included from these files when the solution is built. When you are compiling from the command line, all source files must appear as command-line arguments to the compile command. The location of declarations within source files is unimportant. As long as all referenced declarations appear somewhere in a source file being compiled, they will be found.
Unlike previous versions of Visual Basic, no special file extensions are used to indicate various language constructs (e.g., .cls for classes, .frm for forms, etc.). Syntax has been added to the language to differentiate various constructs. In addition, the pseudolanguage for specifying the graphical layout of forms has been removed. Form layout is specified by setting properties of form objects explicitly within code. Either this code can be written manually, or the WYSIWYG form designer in Visual Studio .NET can write it.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Identifiers
Identifiers are names given to namespaces (discussed later in this chapter), types (enumerations, structures, classes, standard modules, interfaces, and delegates), type members (methods, constructors, events, constants, fields, and properties), and variables. Identifiers must begin with either an alphabetic or underscore character ( _ ), may be of any length, and after the first character must consist of only alphanumeric and underscore characters. Namespace declarations may be declared either with identifiers or qualified identifiers . Qualified identifiers consist of two or more identifiers connected with the dot character ( . ). Only namespace declarations may use qualified identifiers.
Consider this code fragment:
Imports System

Namespace ORelly.ProgVBNet

   Public Class Hello
      Public Shared Sub SayHello(  )
         Console.WriteLine("hello, world")
      End Sub
   End Class

End Namespace
This code fragment declares three identifiers: OReilly.ProgVBNet (a namespace name), Hello (a class name), and SayHello (a method name). In addition to these, the code fragment uses three identifiers declared elsewhere: System (a namespace name), Console (a class name), and WriteLine (a method name).
Although Visual Basic .NET is not case sensitive, the case of identifiers is preserved when applications are compiled. When using Visual Basic .NET components from case-sensitive languages, the caller must use the appropriate case.
Ordinarily, identifiers may not match Visual Basic .NET keywords. If it is necessary to declare or use an identifier that matches a keyword, the identifier must be enclosed in square brackets ([]). Consider this code fragment:
Public Class [Public]
   Public Shared Sub SayHello(  )
      Console.WriteLine("hello, world")
   End Sub
End Class

Public Class SomeOtherClass
   Public Shared Sub SomeOtherMethod(  )
      [Public].SayHello(  )
   End Sub
End Class
This code declares a class named Public and then declares a class and method that use the Public class.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Keywords
Keywords are words with special meaning in a programming language. In Visual Basic .NET, keywords are reserved; that is, they cannot be used as tokens for such purposes as naming variables and subroutines. The keywords in Visual Basic .NET are shown in Table 2-1.
Table 2-1: Visual Basic .NET keywords
Keyword
Description
AddHandler
Visual Basic .NET Statement
AddressOf
Visual Basic .NET Statement
Alias
Used in the Declare statement
And
Boolean operator
AndAlso
Boolean operator
Ansi
Used in the Declare statement
Append
Used as a symbolic constant in the FileOpen function
As
Used in variable declaration (Dim, Friend, etc.)
Assembly
Assembly-level attribute specifier
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Literals
Literals are representations of values within the text of a program. For example, in the following line of code, 10 is a literal, but x and y are not:
x = y * 10
Literals have data types just as variables do. The 10 in this code fragment is interpreted by the compiler as type Integer because it is an integer that falls within the range of the Integer type.
Any integer literal that is within the range of the Integer type (-2147483648 through 2147483647) is interpreted as type Integer, even if the value is small enough to be interpreted as type Byte or Short. Integer literals that are outside the Integer range but are within the range of the Long type (-9223372036854775808 through 9223372036854775807) are interpreted as type Long. Integer literals outside the Long range cause a compile-time error.
Numeric literals can also be of one of the floating point types—Single, Double, and Decimal. For example, in this line of code, 3.14 is a literal of type Double:
z = y * 3.14
In the absence of an explicit indication of type (discussed shortly), Visual Basic .NET interprets floating point literals as type Double. If the literal is outside the range of the Double type (-1.7976931348623157E308 through 1.7976931348623157E308), a compile-time error occurs.
Visual Basic .NET allows programmers to explicitly specify the types of literals. Table 2-2 (shown later in this chapter) lists Visual Basic .NET's intrinsic data types, along with the method for explicitly defining a literal of each type. Note that for some intrinsic types, there is no way to write a literal.
Literals of type String consist of characters enclosed within quotation-mark characters. For example, in the following line of code, "hello, world" is a literal of type String:
Console.WriteLine("hello, world")
String literals are not permitted to span multiple source lines. In other words, this is not permitted:
' Wrong
Console.WriteLine("hello,
   world")
To write a string literal containing quotation-mark characters, type the character twice for each time it should appear. For example:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Types
Types in Visual Basic .NET are divided into two categories: value types and reference types . Value types minimize memory overhead and maximize speed of access, but they lack some features of a fully object-oriented design (such as inheritance). Reference types give full access to object-oriented features, but they impose some memory and speed overhead for managing and accessing objects. When a variable holds a value type, the data itself is stored in the variable. When a variable holds a reference type, a reference to the data (also known as a pointer ) is stored in the variable, and the data itself is stored somewhere else. Visual Basic .NET's primitive types include both value types and reference types (see "Fundamental Types" in this section). For extending the type system, Visual Basic .NET provides syntax for defining both new value types and new reference types (see "Custom Types" later in this section).
All reference types derive from the Object type. To unify the type system, value types can be treated as reference types when needed. This means that all types can derive from the Object type. Treating value types as reference types (a process known as boxing ) is addressed later in this chapter, in Section 2.16.
Visual Basic .NET has several built-in types. Each of these types is an alias for a type supplied by the .NET architecture. Because Visual Basic .NET types are equivalent to the corresponding underlying .NET-supplied types, there are no type-compatibility issues when passing arguments to components developed in other languages. In code, it makes no difference to the compiler whether types are specified using the keyword name for the type or using the underlying .NET type name. For example, the test in this code fragment succeeds:
Dim x As Integer
Dim y As System.Int32
If x.GetType() Is y.GetType(  ) Then
   Console.WriteLine("They're the same type!")
Else
   Console.WriteLine("They're not the same type.")
End If
The fundamental Visual Basic .NET types are:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Namespaces
Thousands of types are defined in the .NET Framework. In addition, programmers can define new types for use in their programs. With so many types, name clashes are inevitable. To prevent name clashes, types are considered to reside inside of namespaces. Often, this fact can be ignored. For example, in Visual Basic .NET a class may be defined like this:
Public Class SomeClass
   ' ...
End Class
This class definition might be in a class library used by third-party customers, or it might be in the same file or the same project as the client code. The client code that uses this class might look something like this:
Dim x As New SomeClass(  )
x.DoSomething(  )
Now consider what happens if the third-party customer also purchases another vendor's class library, which also exposes a SomeClass class. The Visual Basic .NET compiler can't know which definition of SomeClass will be used. The client must therefore use the full name of the type, also known as its fully qualified name . Code that needs to use both types might look something like this:
' The namespace is "FooBarCorp.SuperFoo2100".
Dim x As New FooBarCorp.SuperFoo2100.SomeClass(  )
x.DoSomething(  )
' ...
' The namespace is "MegaBiz.ProductivityTools.WizardMaster".
Dim y As New MegaBiz.ProductivityTools.WizardMaster.SomeClass(  )
y.DoSomethingElse(  )
Note that a namespace name can itself contain periods (.). When looking at a fully qualified type name, everything prior to the final period is the namespace name. The name after the final period is the type name.
Microsoft recommends that namespaces be named according to the format CompanyName . TechnologyName. For example, "Microsoft.VisualBasic".
So how does a component developer specify a type's namespace? In Visual Basic .NET, this can be done several ways. One is to use the Namespace keyword, like this:
Namespace MegaBiz.ProductivityTools.WizardMaster

   Public Class SomeClass
      ' ...
   End Class

End Namespace
Note that it is permissible for different types in the same source file to have different namespaces.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Symbolic Constants
Consider this function:
Public Shared Function RemainingCarbonMass( _
   ByVal InitialMass As Double, _
   ByVal Years As Long _
) As Double
   Return InitialMass * ((0.5 ^ (Years / 5730)))
End Function
What's wrong with this code? One problem is readability. What does it mean to divide Years by 5730? In this code, 5730 is referred to as a magic number -- one whose meaning is not readily evident from examining the code. The following changes correct this problem:
Public Const CarbonHalfLifeInYears As Double = 5730

Public Shared Function RemainingCarbonMass( _
   ByVal InitialMass As Double, _
   ByVal Years As Long _
) As Double
   Return InitialMass * ((0.5 ^ (Years / CarbonHalfLifeInYears)))
End Function
There is now no ambiguity about the meaning of the divisor.
Another problem with the first code fragment is that a program filled with such code is hard to maintain. What if the programmer later discovers that the half-life of carbon is closer to 5730.1 years, and she wants to make the program more accurate? If this number is used in many places throughout the program, it must be changed in every case. The risk is high of missing a case or of changing a number that shouldn't be changed. With the second code fragment, the number needs to be changed in only one place.
See also the discussion of read-only fields later in this chapter, under Section 2.14.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Variables
A variable is an identifier that is declared in a method and that stands for a value within that method. Its value is allowed to change within the method. Each variable is of a particular type, and that type is indicated in the declaration of the variable. For example, this line declares a variable named i whose type is Integer:
Dim i As Integer
The keyword Dim indicates a variable declaration. Dim is short for dimension and dates back to the original days of the BASIC programming language in the late 1960s. In that language, variables were not declared; they were just used where needed (except for arrays). Because of how arrays were laid out in memory, the BASIC language interpreter had to be told of the dimensions of an array before the array was used. This was the purpose of the Dim statement. In later years, when declaration of all variables was agreed upon to be a good thing, the use of the Dim statement was broadened to include all variable declarations.
Variable identifiers may be suffixed with type characters that serve to indicate the variable's type. For example, this line declares a variable of type Integer:
Dim x%
The effect is precisely the same as for this declaration:
Dim x As Integer
The set of type characters is shown in Table 2-4; note that not all data types have a type character.
Table 2-4: Type characters
Data type
Type character
Example
Decimal
@
Dim decValue@ = 132.24
Double
#
Dim dblValue# = .0000001327
Integer
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Scope
Scope refers to the so-called visibility of identifiers within source code. That is, given a particular identifier declaration, the scope of the identifier determines where it is legal to reference that identifier in code. For example, these two functions each declare a variable CoffeeBreaks. Each declaration is invisible to the code in the other method. The scope of each variable is the method in which it is declared.
Public Sub MyFirstMethod(  )
   Dim CoffeeBreaks As Integer
   ' ...
End Sub
 
Public Sub MySecondMethod(  )
   Dim CoffeeBreaks As Long
   ' ...
End Sub
Unlike previous versions of Visual Basic, Visual Basic .NET has block scope . Variables declared within a set of statements ending with End, Loop, or Next are local to that block. For example:
Dim i As Integer
For i = 1 To 100
   Dim j As Integer
   For j = 1 To 100
      ' ...
   Next
Next
' j is not visible here
Visual Basic .NET doesn't permit the same variable name to be declared at both the method level and the block level. Further, the life of the block-level variable is equal to the life of the method. This means that if the block is re-entered, the variable may contain an old value (don't count on this behavior, as it is not guaranteed and is the kind of thing that might change in future versions of Visual Basic).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Access Modifiers
Access modifiers control the accessibility of types (including enumerations, structures, classes, standard modules, and delegates) and type members (including methods, constructors, events, constants, fields [data members], and properties) to other program elements. They are part of the declarations of types and type members. In the following code fragment, for example, the keywords Public and Private are access modifiers:
Public Class SomeClass
 
   Public Sub DoSomething(  )
      ' ...
   End Sub
 
   Private Sub InternalHelperSub(  )
      ' ...
   End Sub
   
End Class
The complete list of access modifiers and their meanings is shown in Table 2-5.
Table 2-5: Access modifiers
Access modifier
Description
Friend
Defines a type that is accessible only from within the program in which it is declared.
Private
Defines a type that is accessible only from within the context in which it is declared. For instance, a Private variable declared within a class module is accessible only from within that class module. A Private class is accessible only from classes within which it is nested.
Protected
Applies to class members only. Defines a type that is accessible only from within its own class or from a derived class.
Protected Friend
Defines a type that is accessible from within the program in which it is declared as well as from derived classes.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Assignment
In Visual Basic .NET, assignment statements are of the form:
variable, 
field, or 
property = 
expression
Either the type of the expression must be the same as that of the item receiving the assignment, or there must exist an appropriate implicit or explicit conversion from the type of the expression to the type of the item receiving the assignment. For information on implicit and explicit conversions, see Section 2.5.5 earlier in this chapter.
When an assignment is made to a value type, the value of the expression is copied to the target. In contrast, when an assignment is made to a reference type, a reference to the value is stored in the target. This is an important distinction that is worth understanding well. Consider the code in Example 2-3.
Example 2-3. Value-type assignment versus reference-type assignment
Public Structure SomeStructure
   Public MyPublicMember As String
End Structure

Public Class SomeClass
   Public MyPublicMember As String
End Class

Public Class AssignmentTest
   
   Public Shared Sub TestValueAndReferenceAssignment(  )
   
      Dim a, b As SomeStructure
      Dim c, d As SomeClass
      
      ' Test assignment to value type.
      a.MyPublicMember = "To be copied to 'b'"
      b = a
      a.MyPublicMember = "New value for 'a'"
      Console.WriteLine("The value of b.MyPublicMember is """ _
         & b.MyPublicMember & """")
      
      ' Test assignment to reference type.
      c = New SomeClass(  )
      c.MyPublicMember = "To be copied to 'd'"
      d = c
      c.MyPublicMember = "New value for 'c'"
      Console.WriteLine("The value of d.MyPublicMember is """ _
         & d.MyPublicMember & """")
      
   End Sub
   
End Class
The output of the TestValueAndReferenceAssignment method in Example 2-3 is:
The value of b.MyPublicMember is "To be copied to 'b'"
The value of d.MyPublicMember is "New value for 'c'"
In Example 2-3, the SomeStructure structure and the SomeClass class have identical definitions, except that one is a structure and the other is a class. This leads to very different behavior during assignment. When a value type is copied, the actual value is copied. When a reference type is copied, only the reference is copied, resulting in two references to the same value. If the value is subsequently changed through one of the references, the new value is also seen through the other reference.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Operators and Expressions
Operators are symbols (characters or keywords) that specify operations to be performed on one or two operands (or arguments ). Operators that take one operand are called unary operators. Operators that take two operands are called binary operators. Unary operators use prefix notation , meaning that the operator precedes the operand (e.g., -5). Binary operators (except for one case) use infix notation , meaning that the operator is between the operands (e.g., 1 + 2). The TypeOf...Is operator is a binary operator that uses a special form that is neither prefix nor infix notation.
Visual Basic supports the following unary operators:
+ (unary plus)
The unary plus operator takes any numeric operand. It's not of much practical use because the value of the operation is equal to the value of the operand.
- (unary minus)
The unary minus operator takes any numeric operand (except as noted later). The value of the operation is the negative of the value of the operand. In other words, the result is calculated by subtracting the operand from zero. If the operand type is Short, Integer, or Long, and the value of the operand is the maximum negative value for that type, then applying the unary minus operator will cause a System.OverflowException error, as in the following code fragment:
Dim sh As Short = -32768
Dim i As Integer = -sh
Not (logical negation)
The logical negation operator takes a Boolean operand. The result is the logical negation of the operand. That is, if the operand is False, the result of the operation is True, and vice versa.
AddressOf
The AddressOf operator returns a reference to a method. Two different kinds of references can be obtained, depending on the context in which the operator is used:
  • When the AddressOf operator is used within the argument list of a call to a method, which is made available via the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Statements
Visual Basic .NET is a line-oriented language, in which line breaks generally indicate the ends of statements. However, there are times when a programmer may wish to extend a statement over several lines or have more than one statement on a single line.
To extend a statement over several lines, use the line-continuation character, an underscore (_). It must be the last character on its line, and it must be immediately preceded by a space character. Lines connected in this way become a single logical line. Here is an example:
Dim strSql As String = "SELECT Customers.CompanyName," _
   & " COUNT(Orders.OrderID) AS OrderCount" _
   & " FROM Customers INNER JOIN Orders" _
   & " ON Customers.CustomerID = Orders.CustomerID" _
   & " GROUP BY Customers.CompanyName" _
   & " ORDER BY OrderCount DESC"
A line break can occur only where whitespace is allowed.
To place two or more statements on a single line, use the colon (:) between the statements, like this:
i = 5 : j = 10
The remainder of this section discusses the statements in Visual Basic .NET.
There are three Option statements, which affect the behavior of the compiler. If used, they must appear before any declarations in the same source file. They control the compilation of the source code in the file in which they appear. They are:
Option Compare
The Option Compare statement controls the manner in which strings are compared to each other. The syntax is:
Option Compare [ Binary | Text ]
If Binary is specified, strings are compared based on their internal binary representation (i.e., string comparisons are case-sensitive). If Text is specified, strings are compared based on case-insensitive alphabetical order. The default is Binary.
Option Explicit
The Option Explicit statement determines whether the compiler requires all variables to be explicitly declared. The syntax is:
Option Explicit [ On | Off ]
If On is specified, the compiler requires all variables to be declared. If
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Classes
A class is one form of data type. As such, a class can be used in contexts where types are expected—in variable declarations, for example. In object-oriented design, classes are intended to represent the definition of real-world objects, such as customer, order, product, etc. The class is only the definition, not an object itself. An object would be a customer, an order, or a product. A class declaration defines the set of members—fields, properties, methods, and events—that each object of that class possesses. Together, these members define an object's state, as well as its functionality. An object is also referred to as an instance of a class. Creating an object of a certain class is called instantiating an object of the class.
Consider the class definition in Example 2-4.
Example 2-4. A class definition
Public Class Employee

   Public EmployeeNumber As Integer
   Public FamilyName As String
   Public GivenName As String
   Public DateOfBirth As Date
   Public Salary As Decimal

   Public Function Format(  ) As String
      Return GivenName & " " & FamilyName
   End Function
   
End Class
The code in Example 2-4 defines a class called Employee. It has five public fields (also known as data members ) for storing state, as well as one member function . The class could be used as shown in Example 2-5.
Example 2-5. Using a class
Dim emp As New Employee(  )

emp.EmployeeNumber = 10
emp.FamilyName = "Rodriguez"
emp.GivenName = "Celia"
emp.DateOfBirth = #1/28/1965#
emp.Salary = 115000

Console.WriteLine("Employee Name: " & emp.Format(  ))
Console.WriteLine("Employee Number: " & emp.EmployeeNumber)
Console.WriteLine("Date of Birth: " & emp.DateOfBirth.ToString("D", Nothing))
Console.WriteLine("Salary: " & emp.Salary.ToString("C", Nothing))
The resulting output is:
Employee Name: Celia Rodriguez
Employee Number: 10
Date of Birth: Thursday, January 28, 1965
Salary: $115,000.00
Object instantiation is done using the New keyword. The New keyword is, in effect, a unary operator that takes a type identifier as its operand. The result of the operation is a reference to a newly created object of the given type. Consider the following:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Interfaces
It is useful to make a distinction between a class's interface and its implementation. Conceptually, the interface of a class is the set of members that are visible to users of the class—i.e., the class's public members. The public members are thought of as comprising the class's interface because they are the only way that code outside of the class can interact (i.e., interface) with objects of that class. In contrast, the implementation is comprised of the class's code plus the set of members that are not public.
It is possible to take this interface concept further and separate interface definition from class definition altogether. This has benefits that will be shown shortly. To define an interface, use the Interface statement:
Public Interface ISomeInterface
   Sub SomeSub(  )
   Function SomeFunction(  ) As Integer
   Property SomeProperty(  ) As String
   Event SomeEvent( _
      ByVal sender As Object, _
      ByVal e As SomeEventArgs _
   )
End Interface
An interface declaration defines methods, properties, and events that will ultimately be implemented by some class or structure definition. Because interfaces never include any implementation, the declarations are headers only—never any implementation code; End Sub, End Function, or End Property statements; or property get or set blocks. There are no access modifiers (Public, Private, etc.) because all members of an interface are public by definition. By convention, interface names start with the letter "I".
To provide an implementation for a given interface, it is necessary to define a class or structure. For example, the following class implements the interface defined earlier:
Public Class SomeClass
   ' This indicates that the class implements the methods,
   ' properties, and events of the ISomeInterface interface.
   Implements ISomeInterface
   
   ' This method implements the SomeSub method of the
   ' ISomeInterface interface.
   Private Sub SomeSub(  ) Implements ISomeInterface.SomeSub
      ' ...
   End Sub
   
   ' This method implements the SomeFunction method of the
   ' ISomeInterface interface.
   Private Function SomeFunction(  ) As Integer _
      Implements ISomeInterface.SomeFunction
      ' ...
   End Function
   
   ' This property implements the SomeProperty property of the
   ' ISomeInterface interface.
   Private Property SomeProperty(  ) As String _
      Implements ISomeInterface.SomeProperty
      Get
         ' ...
      End Get
      Set
         ' ...
      End Set
   End Property
   
   ' This event implements the SomeEvent event of the
   ' ISomeInterface interface.
   Private Event SomeEvent( _
      ByVal sender As Object, _
      ByVal e As SomeEventArgs _
   ) Implements ISomeInterface.SomeEvent
   
End Class
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Structures
Structures define value types. Variables of a value type store an actual value, as opposed to a reference to a value stored elsewhere. Contrast this with classes, which define reference types. Variables of a reference type store a reference (a pointer) to the actual value. See the discussion of value types versus reference types in Section 2.5 earlier in this chapter. Example 2-8 shows a structure definition.
Example 2-8. A structure definition
Public Structure Complex
   ' The IFormattable interface provides a generic mechanism for
   ' asking a value to represent itself as a string.
   Implements IFormattable

   ' These private members store the value of the complex number.
   Private m_RealPart As Double
   Private m_ImaginaryPart As Double

   ' These fields provide potentially useful values, similar to the
   ' corresponding values in the Double type. They are initialized
   ' in the shared constructor. The ReadOnly modifier indicates that
   ' they can be set only in a constructor.
   Public Shared ReadOnly MaxValue As Complex
   Public Shared ReadOnly MinValue As Complex

   ' This is a shared constructor. It is run once by the runtime
   ' before any other access to the Complex type occurs. Note again
   ' that this is run only once in the life of the program--not once
   ' for each instance. Note also that there is never an access
   ' modifier on shared constructors.
   Shared Sub New(  )
      MaxValue = New Complex(Double.MaxValue, Double.MaxValue)
      MinValue = New Complex(Double.MinValue, Double.MinValue)
   End Sub

   ' The RealPart property gives access to the real part of the
   ' complex number.
   Public Property RealPart(  ) As Double
      Get
         Return m_RealPart
      End Get
      Set(ByVal Value As Double)
         m_RealPart = Value
      End Set
   End Property

   ' The ImaginaryPart property gives access to the imaginary part
   ' of the complex number.
   Public Property ImaginaryPart(  ) As Double
      Get
         Return m_ImaginaryPart
      End Get
      Set(ByVal Value As Double)
         m_ImaginaryPart = Value
      End Set
   End Property

   ' This is a parameterized constructor allowing initialization of
   ' a complex number with its real and imaginary values.
   Public Sub New( _
      ByVal RealPart As Double, _
      ByVal ImaginaryPart As Double _
   )
      m_RealPart = RealPart
      m_ImaginaryPart = ImaginaryPart
   End Sub

   ' This function computes the sum of two Complex values.
   Public Shared Function Add( _
      ByVal Value1 As Complex, _
      ByVal Value2 As Complex _
   ) As Complex
      Dim retval As Complex
      retval.RealPart = Value1.RealPart + Value2.RealPart
      retval.ImaginaryPart = Value1.ImaginaryPart + Value2.ImaginaryPart
      Return retval
   End Function

   ' This function computes the difference of two Complex values.
   Public Shared Function Subtract( _
      ByVal Value1 As Complex, _
      ByVal Value2 As Complex _
   ) As Complex
      Dim retval As Complex
      retval.RealPart = Value1.RealPart - Value2.RealPart
      retval.ImaginaryPart = Value1.ImaginaryPart - Value2.ImaginaryPart
      Return retval
   End Function

   ' This function computes the product of two Complex values.
   Public Shared Function Multiply( _
      ByVal Value1 As Complex, _
      ByVal Value2 As Complex _
   ) As Complex
      Dim retval As Complex
      retval.RealPart = Value1.RealPart * Value2.RealPart _
         - Value1.ImaginaryPart * Value2.ImaginaryPart
      retval.ImaginaryPart = Value1.RealPart * Value2.ImaginaryPart _
         + Value1.ImaginaryPart * Value2.RealPart
      Return retval
   End Function

   ' This function computes the quotient of two Complex values.
   Public Shared Function Divide( _
      ByVal Value1 As Complex, _
      ByVal Value2 As Complex _
   ) As Complex
      Dim retval As Complex
      Dim numerator1 As Double
      Dim numerator2 As Double
      Dim denominator As Double

      numerator1 = Value1.RealPart * Value2.RealPart _
         + Value1.ImaginaryPart * Value2.ImaginaryPart
      numerator2 = Value1.ImaginaryPart * Value2.RealPart _
         - Value1.RealPart * Value2.ImaginaryPart
      denominator = Value2.RealPart ^ 2 + Value2.ImaginaryPart ^ 2

      retval.RealPart = numerator1 / denominator
      retval.ImaginaryPart = numerator2 / denominator
      Return retval
   End Function

   ' This function implements IFormattable.ToString. Because it is
   ' declared Private, this function is not part of the Complex
   ' type's default interface. Note that the function name need
   ' not match the name as declared in the interface, nor need
   ' it be in the format shown here.
   Private Function IFormattable_ToString( _
      ByVal format As String, _
      ByVal formatProvider As IFormatProvider _
   ) As String Implements IFormattable.ToString
      Dim realFormatter As IFormattable = m_RealPart
      Dim imaginaryFormatter As IFormattable = m_ImaginaryPart
      Return realFormatter.ToString(format, formatProvider) & " + " _
         & imaginaryFormatter.ToString(format, formatProvider) & "i"
   End Function

   ' This function formats the Complex value as a string.
   Public Overrides Function ToString(  ) As String
      Return CType(Me, IFormattable).ToString(Nothing, Nothing)
   End Function

End Structure ' Complex
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Enumerations
An enumeration is a type whose values are explicitly named by the creator of the type. The .NET Framework and Visual Basic .NET define many enumerations for their and your use. In addition, Visual Basic .NET provides syntax for defining new enumerations. Here is an example:
Public Enum Rainbow
   Red
   Orange
   Yellow
   Green
   Blue
   Indigo
   Violet
End Enum
This declaration establishes a new type, called Rainbow. The identifiers listed within the body of the declaration become constant values that may be assigned to variables of the Rainbow type. Here is a declaration of a variable of type Rainbow and an initial assignment to it:
Dim myRainbow As Rainbow = Rainbow.Blue
Note that the value name is qualified by the type name.
Enumerations are value types that implicitly inherit from the .NET Framework's System.Enum type (which in turn inherits from System.ValueType). That means that every enumeration has access to the members defined by System.Enum. One such member is the ToString method, which returns a string containing the name of the value. This is handy for printing:
Dim myRainbow As Rainbow = Rainbow.Blue
Console.WriteLine("The value of myRainbow is: " & myRainbow.ToString(  ))
This code results in the following output:
The value of myRainbow is: Blue
The values of an enumeration are considered as ordered. Thus, comparisons are permitted between variables of the enumeration type:
Dim myRainbow As Rainbow
Dim yourRainbow As Rainbow
' ...
If myRainbow < yourRainbow Then
   ' ...
End If
Variables of an enumeration type can be used as indexes in For...Next statements. For example:
For myRainbow = Rainbow.Red To Rainbow.Violet
   ' ...
Next
Internally, Visual Basic .NET and the .NET Framework use values of type Integer to represent the values of the enumeration. The compiler starts with 0 and assigns increasing Integer values to each name in the enumeration. It is sometimes useful to override the default Integer values that are assigned to each name. This is done by adding an initializer to each enumeration constant. For example:
Public Enum MyLegacyErrorCodes
   NoError = 0
   FileNotFound = -1000
   OutOfMemory = -1001
   InvalidEntry = -2000
End Enum
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Exceptions
Sometimes errors or exceptional conditions prohibit a program from continuing its current activity. A classic example is division by zero:
Dim x As Integer = 0
Dim y As Integer = 1 \ x
When the process hits the line containing the integer division, an exception occurs. An exception is any occurrence that is not considered part of normal, expected program flow. The runtime detects, or catches, this exception and takes appropriate action, generally resulting in termination of the offending program. Figure 2-3 shows the message box that is displayed when this code is run within the Visual Studio .NET IDE.
Figure 2-3: A divide-by-zero exception
Visual Basic .NET programs can and should be written to catch exceptions themselves. This is done by wrapping potentially dangerous code in Try...End Try blocks. Example 2-9 shows how to catch the divide-by-zero exception.
Example 2-9. Catching an exception
Try
   Dim x As Integer = 0
   Dim y As Integer = 1 \ x
Catch e As Exception
   Console.WriteLine(e.Message)
End Try
When the program attempts the division by zero, an exception occurs, and program execution jumps to the first statement in the Catch block. The Catch statement declares a variable of type Exception that receives information about the exception that occurred. This information can then be used within the Catch block to record or report the exception, or to take corrective action. The previous code merely displays the message associated with the exception that occurred, as shown here:
Attempted to divide by zero.
After executing the statements in the Catch block, program execution continues with whatever follows the End Try statement. In Try blocks in which no exception occurs, execution continues through to the last statement of the Try block and then skips the statements in the Catch block.
The variable declared in the Catch statement of Example 2-9 is of type Exception (defined in the System namespace). All exceptions are represented by types that derive, either directly or indirectly, from the Exception type. The
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Delegates
A delegate is a programmer-defined type that abstracts the ability to call a method. A delegate-type declaration includes the declaration of the signature and return type that the delegate encapsulates. Instances of the delegate type can then wrap any method that exposes the same signature and return type, regardless of the class on which the method is defined and whether the method is an instance method or shared method of the defining class. The method thus wrapped can be invoked through the delegate object. The delegate mechanism provides polymorphism for methods having the same signature and return type.
Delegates are often used to implement callback mechanisms. Imagine a class that will be used by a program you are writing. This class provides some useful functionality, including the ability to call in to a method that you must implement within your program. Perhaps this callback mechanism is provided to feed your program data as it becomes available in the class you are using. One way to achieve this capability is through the use of delegates. Here's how:
  1. The writer of the class you're using (call it a server class) declares a public delegate type that defines the signature and return value of the method that you will implement.
  2. The writer of the server class exposes a method for clients of the class to pass in an instance of the delegate type.
  3. You implement a method having the appropriate signature and return value.
  4. You instantiate a new object of the delegate type.
  5. You connect your method to your delegate instance.
  6. You call the method defined in Step 2, passing in your delegate instance.
  7. The server class now has a delegate instance that wraps your method. The class can call your method through the delegate at any time.
  8. Depending on the application, it might be appropriate for the writer of the server class to provide a method that allows the client application to disconnect its delegate from the server to stop receiving callbacks.
Example 2-13 shows an example of this mechanism.
Example 2-13. Defining and using a delegate type to implement a callback mechanism
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Events
An event is a callback mechanism. With it, objects can notify users that something interesting has happened. If desired, data can be passed from the object to the client as part of the notification. Throughout this section, I use the terms event producer , producer class , and producer object to talk about a class (and its instances) capable of raising events. I use the terms event consumer , consumer class , and consumer object to talk about a class (and its instances) capable of receiving and acting on events raised by an event producer.
Here is a class that exposes an event:
Public Class EventProducer

   Public Event SomeEvent(  )

   Public Sub DoSomething(  )
      ' ...
      RaiseEvent SomeEvent(  )
      ' ...
   End Sub

End Class
The Event statement in this code fragment declares that this class is capable of raising an event called SomeEvent. The empty parentheses in the declaration indicate that the event will not pass any data. An example later in this section will show how to define events that pass data.
The RaiseEvent statement in the DoSomething method raises the event. Any clients of the object that have registered their desire to receive this event will receive it at this time. Receiving an event means that a method will be called on the client to handle the event. Here is the definition of a client class that receives and handles events from the EventProducer class:
Public Class EventConsumer

   Private WithEvents producer As EventProducer

   Public Sub producer_SomeEvent(  ) Handles producer.SomeEvent
      Console.WriteLine("Hey, an event happened!!")
   End Sub

   Public Sub New(  )
      producer() = New EventProducer(  )
   End Sub

   Public Sub DoSomething(  )
      ' ...
      producer().DoSomething(  )
      ' ...
   End Sub

End Class
The key aspects here are:
  • The consumer object has a field that contains a reference to the producer object.
  • The consumer object has a method capable of handling the event. A method is capable of handling an event if the method and event have the same signature. The name of the method is not important.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Standard Modules
A standard module is a type declaration. It is introduced with the Module statement, as shown here:
Public Module ModuleTest
   ' ...
End Module
Don't confuse the Visual Basic .NET term, standard module, with the .NET term, module. They are unrelated to each other. See Chapter 3 for information about .NET modules.
Standard module definitions are similar to class definitions, with these differences:
  • Standard module members are implicitly shared.
  • Standard modules cannot be inherited.
  • The members in a standard module can be referenced without being qualified with the standard module name.