Home > Articles > Programming > Windows Programming

  • Print
  • + Share This
This chapter is from the book

Functional Changes

In addition to the syntactical changes, VB .NET behaves differently from previous versions in several respects. This section details the most significant of those changes.

Declarations

Several of the most obvious and productivity-enhancing changes in the language are related to dimensioning and instantiating variables.

As you might be aware through painful experience, in prior versions, a declaration like so

Dim x,y,z As Integer

did not result in three Integer variables. In fact, the first two variables were declared as Variant, which wastes memory and has the potential of causing type conversion problems down the road. In VB .NET, multiple declarations work as expected, and so the same declaration will result in three Integer variables. In addition, VB .NET supports the capability to use the declaration

Dim z

when the Option Strict statement is set to Off. In this case, rather than result in a Variant, the variable z is of type System.Object. Also note that unlike in previous versions, Option Explicit is defaulted to On so that variables cannot be used without first declaring them.

VB .NET also supports parameterized constructors so that objects can be initialized during the declaration. This, coupled with support for initialization during declaration, allows VB .NET to support the following types of syntax:

Dim dtAaron As New DateTime(1974, 4, 8)
Dim strName As String = "Hank Aaron"
Dim arTheropods() As String = {"Tyrannosaur", "Allosaurus", "Deinonychus"}

In this example, the dtAaron variable is declared as a DateTime structure and instantiated with arguments passed to the constructor specifying the day Hank Aaron hit his 715th homerun. This is shorthand for the statement:

Dim dtAaron As DateTime = New DateTime(1974, 4, 8)

In the second example, VB .NET takes care of calling the constructor for the String variable to allow developers to work with strings in a familiar fashion. The third example shows how to initialize an array of strings during declaration.

TIP

Although the constants you would expect (those prefixed with "vb") exist within the Microsoft.VisualBasic namespace, they also are exposed through enumerated types. Because the methods of the namespace expect the enumerated types, it is recommended that you use them rather than the constants.

Object Creation

Two other changes from the behavior of previous versions of VB are related to the creation of objects using the New operator. In previous versions the statement

Dim dino As New Dinosaur

would result in the compiler actually wrapping each line of code that referenced dino with a check to see whether the variable was Nothing. If so, the object was instantiated. In VB .NET, implicit object creation is not supported, and so the object is instantiated when the Dim statement is encountered. As a result, if you're going to use the New operator in a declaration, you'll want to place the declaration within the procedure in a place you know the variable will be used. In other words, it is more efficient if you defer dimensioning variables that might end up not being used, as long as possible.

In addition, in VB 6.0, the New operator actually used an internal algorithm that was more efficient to instantiate classes within the same project. In VB .NET, the CLR creates and manages all object instances, and so there is no difference when New is used with classes in the local assembly versus a remote assembly.

Finally, the CreateObject function, although still supported, will only be used to create a COM object. All managed classes are instantiated with the New keyword.

Operators

As shown in Table 3.2, VB .NET adds support for new operators. Perhaps the most significant from a keystroke-saving perspective are the operators that perform their operation and assign the result to the variable. For example, in VB 6.0, to concatenate a string on two lines, you would do the following:

Dim strMessage As String

strMessage = "This is a message that will be pretty long,"
strMessage = strMessage & " so I'll break it up a little."

In VB .NET, this can be compacted to the following:

strMessage = "This is a message that will be pretty long,"
strMessage &= " so I'll break it up a little."

In addition to concatenation, addition, subtraction, multiplication, division, and exponentiation are supported using this compacted syntax.

VB .NET also does not support default properties, and so the statement

Text1 = strName

does not assign the string variable strName to the Text property of the Text1 object. As a result, you must explicitly use the property. The good news is that this means the Set and Let statements, which caused a good deal of confusion, are no longer required or supported. The one exception to default properties is in the case where the property accepts a parameter. In this instance, you can mark the property as the default so that working with objects that support collections through properties such as Item is simplified.

Operators evaluation in expressions also can be short-circuited in VB .NET so that a procedure like the one that follows can be more efficient:

Sub Insert(ByVal value As Integer, ByVal sortedArr() As Integer)
  Dim intIndex, intIndxSrch As Integer
  Dim intArrCount As Integer = sortedArr.Length

  `Scan for entry less than one to be inserted
  While intIndxSrch < intArrCount AndAlso value > sortedArr(intIndxSrch)
    intIndxSrch += 1
  End While

  `Make room for new value --- move remaining items up
End Sub

In this example, the Insert procedure inserts a new value in a sorted array. Note that the While loop contains the new AndAlso operator with two expressions. Using short-circuit evaluation, the second condition, which is the more expensive of the two, will not be executed if the first condition returns False. In the past, you needed to place these conditions on separate lines to gain this efficiency. Short-circuiting also is implemented with the new OrElse operator when the first expression evaluates to True.

NOTE

Although it was originally planned that the And, Or, Not, and Xor operators would only perform logical and not bitwise operations, feedback from the VB community ensured that these retain both functionalities and precedence rules as in VB 6.0.

Although not documented in VB 6.0, some developers became accustomed to using the VarPtr, VarPtrArray, VarPtrStringArray, ObjPtr, and StrPtr operators to return the memory addresses of variables of these data types. This was particularly useful when calling some Win32 API functions. These keywords are no longer supported in VB .NET.

Closely related to operators is the behavior of null values. In VB 6.0, null propagation was supported where adding or concatenating a value to Null, or a Variant that contained Null, always produced a null value. In VB .NET, Null has been replaced with Nothing, Variant with Object, and null propagation is not supported. As a result, the following behavior occurs in VB .NET when Option Strict is set to Off:

Dim x As Object
Dim i As Integer

i = 4
x = Nothing
i = i + x  ` i still equals 4

The Null keyword has been replaced with the System.DBNull class, and checking for nulls returned from databases can be done using the IsDBNull function. The equivalent syntax used in VB 6.0, where an empty string ("") concatenated to a null from a database produced an empty string, is still supported as well.

The absence of both variants and null values implies that functions that once accepted variants and possibly returned null values, such as Mid, Oct, Right, RTrim, Space, Str, Time, Trim, LTrim, UCase, and LCase, among others, now simply return their associated data types. As mentioned in Table 3.1, VB 6.0 also contained companion functions appended with $ (i.e. Trim$) that returned String values. These also have been replaced with overloaded methods that return a String.

Data Types

As discussed in Chapter 1, "The Microsoft .NET Architecture," all data types in VB .NET derive from System.Object and are therefore a part of the Common Type System (CTS) used by the CLR. VB .NET supports keywords that map to the CTS types shown in Table 1.1. This mapping is shown in Table 3.3.

Table 3.3  Data Type Mappings in VB .NET

VB .NET Data Type (with type character)

CTS Type

Boolean

System.Boolean

Byte

System.Byte

Char (new)

System.Char

Decimal (@) (new)

System.Decimal

Double (#)

System.Double

Integer (%)

System.Int32

Long (&)

System.Int64

Short (new)

System.Int16

Single (!)

System.Single

String ($)

System.String

As in VB 6.0, the type character can be used to automatically dimension a variable by appending it to the declaration. For example,

Dim z%

ensures that z is an Integer. However, because type characters make the code less readable, they are not recommended.

In addition, several of the data types include special characters (literal type characters) that can be used with literal values to force their representation to the appropriate type. These include C (Char), D (Decimal), R (Double), I (Integer), L (Long), S (Short), and F (Single). In other words, the statement

Dim b As Object

b = "T"C

forces the variable b to the type Char.

One of the most interesting aspects of Table 3.3, though, is the representation of integers. In VB 6.0, the Integer data type was 16 bits, and so the range was from -32,768 to 32,768. However, with the inclusion of Short to fill that spot, Integer is now a 32-bit value that is equivalent to the Long data type in VB 6.0. In turn, Long is now 64 bits with a range from ±9,223,372,036,854,775,808. Although this is desired because it brings VB .NET inline with other modern programming languages and applications, such as SQL Server, keep in mind that if you're porting existing code or rewriting code from VB 6.0 you'll want to change the data types as appropriate.

The internal representation of several data types in the CLR also is different from previous versions of VB. For example, the Boolean data type in VB 6.0 equated to -1 for True and 0 for False. Now, the more standard 0 for False and 1 for True is used by the runtime. However, to maintain backwards compatibility when working in VB .NET, the older -1 and 0 will be used. Keep in mind, though, that converting a Boolean to a CTS type such as System.Int32, or passing a Boolean to another managed language, will convert the result back to a 1 for True and 0 for False. Also, as mentioned in Table 3.3, the Date data type is no longer represented as a Double; it is mapped to System.DateTime, and implicit conversion between the two is no longer supported. Explicit conversion, however, can be accomplished by using the ToDouble and FromOADate methods of the DateTime class.

Of course, as should be obvious by now, the universal data type in previous versions of VB, the Variant, has been replaced with Object. The Object keyword used in VB 6.0 to refer to a late bound object has been subsumed into this definition.

Finally, as shown in Table 3.1 the Currency data type is no longer supported in VB .NET and has been replaced with the Decimal data type.

Arrays

There are several important changes in VB .NET with regards to arrays. First, the lower bound of an array can no longer be set using the Option Base statement. As a result, the syntax

Dim s(0 to 10) As String

no longer is supported because all arrays are zero bound.

NOTE

The designers of VB .NET originally planned that the array declaration would specify the number of elements and not the upper bound. In other words, the declaration

    Dim s(10) As String

would produce an array of 10 elements with indices from 0 through 9. However, this changed shortly before the beta 2 was released based on feedback from the VB community.

Also in VB .NET, by default, all arrays are variable-sized arrays, so they all can be resized using the ReDim statement. However, the ReDim statement cannot be used in place of the Dim statement to dimension an array as in VB 6.0.

In addition, as seen previously, an array can be populated in the declaration using the { } brackets like so:

Dim sosaHomers() As Short = {66, 63, 50, 64}

This syntax replaces the Array function formerly used to populate an array with arguments passed to the function. VB .NET still supports multidimensional arrays; however, the number of dimensions (referred to as the rank) must be set in the Dim statement. For example, the code

Dim arPlayers(,) As String
ReDim arPlayers(1, 3)

arPlayers(0, 0) = "Pitcher"
arPlayers(0, 1) = "Catcher"
arPlayers(0, 2) = "1B"
arPlayers(0, 3) = "2B"

arPlayers(1, 0) = "Roger Clemens"
arPlayers(1, 1) = "Mike Piazza"
arPlayers(1, 2) = "Mark McGwire"
arPlayers(1, 3) = "Eric Young"

works in VB .NET because the comma in the Dim statement denotes that there are two dimensions to the array. The same declaration without the comma works in VB 6.0. As in VB 6.0, VB .NET also allows you to change the upper bound of the last dimension in the array while preserving the contents of the array, and so the statement

ReDim Preserve arPlayers(1, 4)

immediately after the preceding code example successfully adds another element to the second dimension. The Preserve keyword ensures that the data is preserved.

TIP

As in VB 6.0, if you don't know the rank the array will have at development time, then dimension the array simply As Array or As Object.

VB .NET also still supports ragged arrays or arrays of arrays, which, like multidimensional arrays, allow you to store tabular type data but allow a varying number of elements. For example, the code in Listing 3.1 shows how you would create a ragged array by dimensioning the array As Object and then placing arrays inside it.

Listing 3.1  Creating Ragged Arrays in VB .NET. To create a ragged array use the Object type.

Dim a As Object
Dim b(0) As String
Dim c(1) As String
Dim obj As Object
Dim obj1 As Object

ReDim a(2)

` Fill the inner arrays
c(0) = "c1"
c(1) = "c2"
b(0) = "b1"

` Set the elements of the outer array
a(0) = b
a(1) = c
a(2) = "Third element"

` Traverse the contents of the array
For Each obj In a
    If IsArray(obj) Then
       For Each obj1 In obj
           Console.WriteLine(obj1.ToString)
       Next
    Else
        Console.WriteLine(obj.ToString)
    End If
Next

Note that Option Strict must be set to Off for this code to compile because late binding is occurring in the array referenced as a. Although this works in VB .NET, you might want to stick with multidimensional arrays because ragged arrays are not CLS compliant, and passing such an array to managed code written in another language might not work.

Many of these changes are made possible by the fact that all arrays in VB .NET are ultimately derived from System.Array. This class supports several shared methods that can be used to manipulate arrays as well as instance methods that can return data on a particular array. As you would expect, because System.Array is a reference type, assigning a variable to an existing array creates a reference to the array rather than a copy of it. To get a copy, you can use the Clone method of the Array class.

TIP

Shared methods can be called on a class without first instantiating an object from the class. This allows the class to contain various helper functions that can be used in a variety of situations. Conversely, instance methods are those that work on the current instance of the class.

For example, the declaration of the arPlayers array in VB .NET is actually translated to this:

Dim arPlayers As Array

arPlayers = Array.CreateInstance(GetType(String), 2, 4)

Note that the sizes of the dimensions as specified in the last two arguments to the CreateInstance method are set to 2 and 4, rather than 1 and 3 as you might expect. This is the case because arrays in the CLR typically are declared using the size of a dimension rather than the upper bound.

Even if the array is created in standard VB .NET syntax, all the Array methods and properties are available, the most important of which are shown in Table 3.4.

Table 3.4  Array Class Members

Member

Description

BinarySearch

Shared method that searches a one-dimensional array for a specific element

Clear

Shared method that sets a range of the array to zero or Nothing

Copy

Shared method that copies a section of one array to another array

CreateInstance

Shared method that initializes a new instance of the Array class

IndexOf

Shared method that returns the index of the first occurrence of a given value in a one-dimensional array

LastIndexOf

Shared method that returns the last index of the first occurrence of a given value in a one-dimensional array

Reverse

Shared method that reverses the order of elements in a one-dimensional array

Sort

Shared method that sorts the elements of a one-dimensional array

IsFixedSize

Instance property that returns True if the array is fixed size

IsReadOnly

Instance property that returns whether the array is read-only

IsSynchronized

Instance property that returns whether access to the array is thread-safe

Length

Instance property that returns the total number of elements in all dimensions of the array

Rank

Instance property that returns the number of dimensions

SyncRoot

Instance property that returns an object that can be used to synchronize access to the array

Clone

Instance method that creates a copy of the array

CopyTo

Instance method that copies all or part of a one-dimensional array to another array

GetLength

Instance method that returns the number of elements from a specified dimension of the array

GetLowerBound

Instance method that returns the lower bound of a specified dimension of the array

GetUpperBound

Instance method that returns the upper bound of a specified dimension of the array

GetValue

Instance method that returns the specified values in the one-dimensional array

SetValue

Instance method that sets the specified values in the one-dimensional array

Initialize

Instance method that initializes every element of a value-type array if it has a constructor

To illustrate the use of the Array class, consider the procedure in Listing 3.2 used to find a specific item in an array.

Listing 3.2  Using the Array Class. This method exercises some of the functionality of the Array class to sort and search the array.

Function FindVal(ByVal value As Object, ByRef arr As Array) As Integer
  Dim intIndex As Integer

  If Not IsArray(Arr) Then
    Throw New ArgumentException( _
      "Argument is not an array or array has no elements")
    Return -1
  End If

  Try
    ` Sort the array
    Array.Sort(arr)
    ` Do a search
    intIndex = Array.BinarySearch(arr, value)
  Catch e As Exception
    Throw New Exception( _
      "There was an error working with the array: " & e.Message)
    Return -1
  End Try

  ` Negative if not found
  If intIndex < 0 Then
    Return -1
  Else
    Return intIndex
  End If

End Function

In this example, note that the FindVal procedure accepts an argument declared As Object to search for in the array, along with the array, and returns the index at which the value was found. The new IsArray function is used to determine whether the array has been initialized. If so, the array is first sorted using the Sort method and then a binary search is performed using BinarySearch. The return value from BinarySearch will be negative if the value is not found. Note that by definition, the BinarySearch method is case sensitive. In this case, the method returns the index of the element if the value is found, and a -1 if not. Since the array is passed to the method by reference, the array will be sorted when the method returns and the index will point to the new position of the value within the sorted array.

NOTE

Many of the methods of the Array class work only with one-dimensional arrays. If you attempt to call these methods on multidimensional arrays, exceptions will be thrown. To work with, sort, and search multidimensional arrays, you'll need to employ your own techniques. Some of these can be found in Chapter 24 of my book Pure Visual Basic.

Alternatives to Arrays

Although arrays in VB .NET are easily mapped to the System.Array type, they are not always ideal for manipulating data within your application. To provide more choice and flexibility in working with collections of data, the Services Framework includes the System.Collections and System.Collections.Specialized namespaces. In fact, using these prebuilt collections can offload some of the array manipulation code you would normally write and can greatly improve performance—for example, when needing random access to an in-memory collection of data.

You can think of these namespaces as containing prebuilt data structures for handling data. For example, the System.Collections namespace contains the SortedList class that can be used to store a collection of values and associated keys. As the name implies, the data added to the collection is sorted automatically by the key, and the class contains various methods to access the data either by the key, index, or value. The following code illustrates the use of the SortedList class to store a collection of names:

Dim employees As New SortedList()
Dim i As Integer

employees.Add(3322, "Steve Lake")
employees.Add(6743, "Jody Davis")
employees.Add(1233, "George Mitterwald")
employees.Add(1341, "Tim Hosey")

For i = 0 To employees.Count - 1
  Console.WriteLine("{0}:{1}", _
    employees.GetByIndex(i).ToString, employees.GetKey(i).ToString)
Next

When the For loop is executed, the names are printed in order by their key value.

NOTE

Many of the collection classes include constructors that accept the initial capacity of the collection. Although the capacity of the collection is increased automatically as required through reallocation, this can be used to increase performance when you know ahead of time how many members the collection will contain. In the ArrayList and SortedList classes, the TrimToSize method can subsequently be called to minimize a lists memory overhead.

Although explicating all the classes and their members is beyond the scope of this book, the other types of collections, their descriptions, and uses can be seen in Table 3.5.

Table 3.5  Collection Classes in the System.Collections and System.Collections.Specialized Namespaces

Class

Description

Use

ArrayList

Implements an array that is dynamically sized and able to be sorted

When you need to access the values by index

BitArray

Manages a compact array of bit values represented as true (1) or false (0)

When you need to track a series of switches

Hashtable

Implements a collection of values and associated keys where the key is hashed

When you need to quickly access a value by the key for large collections

HybridDictionary

Implements a ListDictionary when the collection is small and dynamically switches to a HashTable as the collection grows for performance reasons

 

ListDictionary

Implements a linked-list of key-value pairs

When you have fewer than 10 values and need access to them by the key

NameValueCollection

Implements a sorted collection of String keys and values

When you need access to the values by the hash code of the key or the index

Queue

Implements a first-in, first-out collection of objects

When you need to access the values in FIFO order

SortedList

Implements a collection of key-value pairs sorted by the key

When you need to access the values in order by the key

Stack

Implements a last-in, first-out collection objects

When you need to access the values in LIFO order

StringCollection

Implements a collection of strings

-When you need to store strings and access them by index

StringDictionary

Implements a hashtable where the key and value are both strings

When you need to access a large collection of strings by key

The only disadvantage to using most of the collection classes, except the last two shown in Table 3.5, is that they only accept keys and values of type Object. As a result, you'll need to convert the values to the appropriate type when retrieving them from the collection.

Structures

In VB 6.0, data could be grouped together in a user-defined type (UDT) using the Type statement. The UDT then could be instantiated and populated using dot notation and used as a return value from a function or as an argument to a procedure. Further, all the members of the type were public, and the type could only contain fields—no methods, properties, or events.

In VB .NET, the UDT has been replaced with the Structure. A Structure is much more powerful than a UDT. It can contain fields, methods, properties, events, enumerations, and even implement interfaces. In fact, a Structure can be thought of as simply a lightweight class. The primary difference is that a Structure is always a value type as discussed in Chapter 1, and is therefore always copied when used in an assignment statement or passed by value to a procedure. In addition, structures do not support inheritance, and you needn't use the New operator with structures because it is called implicitly in the declaration. However, structures can support constructors, as discussed in Chapter 4. As an example, consider the structure declaration shown in Listing 3.3.

Note that this structure encapsulates information about a baseball player. It contains public fields to represent the attributes of an offensive player—such as the number of hits (H), doubles (D), triples (T), homeruns (HR), and so on—as would be supported in a VB 6.0 Type. In addition, however, it contains public properties to expose the batting average (AVG) and slugging percentage (SLUG) along with a method to calculate the number of runs created (RunsCreated). Finally, the structure contains an enumerated type used to specify the player's position.

Listing 3.3  Player Structure in VB .NET. Note that it looks much like a class.

Structure Player
  Public Sub New(ByVal playerName As String)
    Name = playerName
  End Sub

  Public Enum pPosition
    C = 2
    P = 1
    First = 3
    Second = 4
    Third = 5
    Shortstop = 6
    Left = 7
    Center = 8
    Right = 9
  End Enum

  Public Name As String
  Public H As Integer
  Public D As Integer
  Public T As Integer
  Public HR As Integer
  Public BB As Integer
  Public AB As Integer
  Public SB As Integer
  Public Position As pPosition

  Public ReadOnly Property AVG() As Double
    Get
      Return H / AB
    End Get
  End Property

  Public ReadOnly Property SLUG() As Double
    Get
      Return (H + D + (2 * T) + (3 * HR)) / AB
    End Get
  End Property

  Public Function RunsCreated(ByVal useSB As Boolean) As Double
    If useSB Then
      Return ((H + BB) * (H + D + (2 * T) + (3 * HR) _
        + (0.7 * SB))) / (AB + BB)
    Else
      Return ((H + BB) * (H + D + (2 * T) + (3 * HR))) / (AB + BB)
    End If
  End Function

End Structure

A user of this structure might use the following code to represent the statistics from Sammy Sosa's 2000 season:

Dim sPlayer As Player

With sPlayer
    .Name = "Sammy Sosa"
    .AB = 604
    .H = 193
    .D = 38
    .T = 1
    .HR = 50
    .BB = 91
    .SB = 7
    .Position = Player.pPosition.Right
End With

Console.WriteLine(Math.Round(sPlayer.AVG, 3).ToString)
Console.WriteLine(Math.Round(sPlayer.SLUG, 3).ToString)
Console.WriteLine(Math.Round(sPlayer.RunsCreated(True), 1).ToString)

Because the structure contains a constructor (the New procedure), an alternate declaration would be

Dim sPlayer As New Player("Sammy Sosa")

Conversion

As mentioned in Chapter 1, one of goals of the CLR is to provide a type-safe runtime environment. This means that by default, the CLR will enforce type-safety at compile time by not allowing an object of one type to be assigned to an object of a different type. This behavior is much different from VB 6.0, where type coercion happened implicitly, and VB developers didn't have to worry about statements like the following:

Dim s as String
s = 50

In this case, VB 6.0 implicitly converted the 50 to a string and made the assignment. In VB .NET, this same code will not compile unless the Option Strict statement is used and set to Off. This statement turns off the type-checking feature of the compiler, and then attempts to cast from one type to the other at runtime. In many instances, VB developers feel more comfortable turning off this option although it increases the likelihood of exceptions at runtime.

To perform explicit conversions, you can use the conversion functions (CStr, CBool, CDate, Cint, and so on), the CType and DirectCase functions, or methods of the System.Convert class. The CType function takes the expression to be converted and the type to convert to as parameters. For example, to convert the literal 50 to a string, you would use the following syntax:

s = CType(50, String)

The second argument can be used to explicitly pass a type, as in the preceding example, or you can use the GetType function to extract the type. You'll notice throughout the book that some listings have Option Strict set to Off for ease of coding and to make reading the code for VB developers more natural. The DirectCase function works in much the same way, although is more strict in that it only allows the conversion if the type parsed to it is exactly the same as the type being converted.

However, an easier approach is to use the System.Convert class, which contains seventeen To methods that convert to all of the system data types. In addition, each method supports myriads of overloads to convert from any of the types. Therefore, the previous code example could be rewritten:

s = Convert.ToString(50)

In addition, because all types are ultimately derived from System.Object, you can call the ToString method of any variable to convert it to a String. Calling ToString on a complex type, such as a structure or class, by default simply returns the type name as a string. However, if you define your own classes as described in Chapter 4, you can override the ToString method and return a string representation of your object.

Strings

Like arrays, strings in VB.NET are derived from a base class, in this case System.String, that contains both shared and instance members that allow you to manipulate the string. Table 3.6 shows the important members. Keep in mind that VB .NET also contains string functions in the Microsoft.VisualBasic.Strings module that wrap some of these methods or provide slightly altered functionality. Which technique you use is really a matter of personal preference. Existing VB developers will find the VB .NET functions more familiar, whereas developers new to the Microsoft product set, or coming from ASP, should use the Services Framework for the sake of uniformity among languages.

Table 3.6  String Class Members

Member

Description

Clone

Instance method that returns a new String with the same value

Compare

Shared method that compares two strings and returns an Integer specifying the result

CompareOrdinal

Shared method that compares two strings and returns an Integer specifying the result without taking into account the language or culture

CompareTo

Instance method that compares this instance with a given object

Copy

Shared method that creates a new instance of a String with the same value as the specified string

CopyTo

Instance method that copies a portion of the string to a character array

Concat

Shared method that creates a new String from one or more strings or objects

Empty

Shared constant representing an empty string

EndsWith

Instance method that determines whether a given string matches the end of this string

Equals

Both a shared and instance method that determines whether two strings have the same value

Format

Shared method used to format the string with the given format specification

IndexOf

Instance method that returns the index of the first occurrence of a string within this string

Insert

Instance method that inserts the given string at a given position within this string

Join

Shared method that concatenates a given separator between each element in a given array

LastIndexOf

Instance method that returns the last occurrence of a given string within this string

PadLeft, PadRight

Instance methods that align the current string with spaces or a specified character for a specified length

Remove

Instance method that deletes the specified number of characters from this instance of the string at the specified location

Replace

Instance method that replaces all occurrences of a specified string with the given string

Split

Instance method that splits the string into an array of strings based on a separator

StartsWith

Instance method that determines whether this string is prefixed with a given string

Substring

Instance method that retrieves a substring from the string

ToCharArray

Instance method that copies the characters of the string to a character array

ToLower, ToUpper

Instance methods that return a copy of the string in lower- or uppercase

Trim, TrimEnd, TrimStart

Instance methods that remove spaces or a set of characters from the string

However, even though System.String is a reference type, the contents of a string are immutable, and all the methods that work on a string actually return a new instance of a string in the modified form. For example, to trim a string, the code

Dim s As String

s = "    Some spaces"
s = Trim(s)

actually results in a new string being created and assigned the same variable s. Immutability also affects assignment statements, and so the code

Dim s As String
Dim y As String

s = "Hello"
y = s
s = "New value"

does not change the value of y because y is actually a different string.

Because working with strings in this way can be inefficient for large strings, the Services Framework also contains the StringBuilder class in the System.Text namespace. This class can be used to build strings that can be directly modified perhaps by removing, replacing, or inserting characters, without creating a new string with each modification. For example, if you were to write code that read multiple text files and appended the text from each file to a string, it would be more efficient to use a StringBuilder so that the string could be modified directly, rather than creating a new string with each iteration of the loop. An analogous example is the following code:

Imports System.Text
Dim sbText As New StringBuilder()
Dim i As Integer

sbText.EnsureCapacity(600)

For i = 1 To 50
    sbText.Append("more...")
Next

In this example, the StringBuilder object is instantiated, and its EnsureCapacity method is called to make sure that enough space can be allocated to hold the result. The loop then appends the text to the string. Remember that because the StringBuilder object is not actually a string, you need to use the ToString method to convert it to a string for other uses.

NOTE

The StringBuilder class also is used to allocate string buffers that are filled by unmanaged DLL functions, as is frequently the case with the Win32 API.

VB .NET also does not support fixed-length strings, and so the code that would allocate a 30-character fixed-length string in VB 6.0

Dim s As String * 30

does not compile in VB.NET. The length of a string in VB .NET is determined by its contents only.

Because a string derives from a base class, you would think that you might be able to use a constructor for a string as in

Dim s As New String("E.D. Cope")

However, the String class does not support a constructor that accepts a string. An array of System.Char can be passed to the constructor like so:

Dim arrChar() As Char
arrChar = CType("O. Marsh", Char())
Dim strPaleo As New String(arrChar)

However, if you were going to do this, you would be better off using the initialization technique described earlier in the chapter because it would be more efficient. You would want to use the constructor when initializing a string with a repeated series of characters. The following code initializes a string to 50 spaces:

Dim s As New String(Convert.ToChar(" "), 50)

Finally, as shown in Table 3.6, the String class contains several versions of the Compare and Equals methods that you can use to perform both case-sensitive (the default) and case insensitive comparisons on strings. As in VB 6.0, string comparisons also can be done with the standard operators (=, <>, <, >, >=, <=) using either a binary or text comparison depending on the setting of Option Compare.

Block Scope

In previous versions of VB, variables could be declared at various scopes that included local (procedure), module, class, and global. Although VB .NET retains these scoping rules, it adds a lower level of scoping called the block level.

Block level scoping allows a developer to dimension a variable inside any block statement in VB .NET. These include looping constructs such as the For and While loops, If Then statements, and Try Catch statements, among others. If a variable is declared inside a block, the variables can be accessed only inside that block. For example, in the following code, the variable j is only accessible while in the If Then statement:

Dim i As Integer

If i = 3 Then
    Dim j As Integer
    j = 2
End If

j = 3 ` Causes a compiler error

In this case, the compiler stops you from referencing j outside the block. In addition, the compiler does not let you dimension a variable also called j with local scope. However, a j variable at the module or global level is allowed, although when executing the block, the block variable will be referenced, as you would expect.

Basically, the addition of block scope means that developers can more easily hide data and use it only where appropriate. It is good programming practice to declare variables at the lowest scope available and only raise them to a higher scope when absolutely necessary. This promotes reusability by creating fewer dependencies in your code.

NOTE

Variables in block scope are not deallocated when the block is exited. Block-scoped variables live for the entirety of the procedure they are declared in. When entering the same block several times in the same invocation of the procedure, you might need to initialize the variable.

Procedures

There are several subtle changes in the way VB .NET procedures and functions behave. The following list notes these changes:

  • Perhaps the most important is the change in the default parameter passing mechanism. In VB 6.0, if you did not specify how a parameter was to be passed, it was always passed by reference (ByRef). In VB .NET, this has changed to by-value (ByVal) because many developers didn't take the time to explicitly use the ByVal keyword. Passing parameters by-value protects them from changes inside the procedure, and therefore is safer.

  • TIP

    Although ByVal is now the default, you still should specify it explicitly for readability. In fact, VS .NET does this automatically.

  • In VB 6.0, if you passed the property of an object into a procedure using ByRef, the property was not changed as expected when the procedure ended. This has been corrected in VB .NET, where ByRef arguments work as expected with properties.

  • ParamArray parameters in VB 6.0 were always passed ByRef whereas in VB .NET they are passed ByVal, and the elements of the array must be declared as Object.

  • Arguments marked as Optional in VB 6.0 did not require a default value, whereas in VB .NET, default values are required. This requirement makes the IsMissing keyword obsolete, so it has been removed.

  • Returning data from functions also has changed in VB .NET with the inclusion of the Return keyword. This keyword can be used, rather than setting the return value equal to the name of the function. This makes the code both easier to read and write.

  • The way procedures can be called also has changed. In previous versions of VB, the capability to call a Sub procedure without using parentheses caused a good deal of confusion. In VB .NET, the Call keyword is retained although it is optional, but all procedures that accept arguments must be called with parentheses. If the procedure does not accept arguments, the parentheses are optional, although VS .NET includes them for you anyway. As a result the statement

  • MsgBox "Done with process", vbOK, "Dinosaurs"

    in VB.NET would now be

    MsgBox("Done with process", MsgBoxStyle.OKOnly, "Dinosaurs") 
  • At the procedure declaration level, new access modifiers can be used, covered in Chapter 4.

  • The GoSub statement is no longer supported. Although this has caused much discussion in the VB community, it is probably for the best because developers often can write code that is difficult to maintain with GoSub.

  • A procedure can no longer be marked as Static to automatically make all its local variables static (to retain their values between invocations of the procedure). Now, each variable that is to be static must be declared with the Static keyword.

Using the Compatibility Class

With the core language assembly, VB .NET ships with types that allow you to write code that is more compatible with VB 6.0. This includes classes, interfaces, structures, constants, and enumerated types that are used in VB 6.0.

Primarily, these include types that facilitate the communication between VB 6.0 controls, such as CheckBox and ListBox with classes in the Windows Forms namespace. In addition they include types that are useful for working with the ADO Data Control (ADOC) and implementing data binding. As a result they are not particularly interesting for devleopers of distributed applications.

That being the case, it is not recommended that you use these types in your applications.

  • + Share This
  • 🔖 Save To Your Account