Data Types


Visual Basic .NET Unleashed
By Paul Kimmel
Table of Contents
Chapter 2.  Out with the Old, In with the New

Data Types

Part of the Common Language Runtime is the Common Type System (CTS). To provide cross-language support, .NET defines a type system that describes how types are stored and the allowable values for a type to ensure that the data can be used across languages. For languages to work in the .NET Framework, they need to implement types in accordance with the CTS.

CTS types encompass classes, interfaces, and value types. Types in .NET can have methods , properties, fields, and events, which we will come back to in a minute. What all this means to Visual Basic .NET is that types and acceptable values for those types that you've become familiar with have changed to support .NET. This section describes changes to existing types and the introduction of new types. (For a comprehensive discussion of the .NET Framework, see Chapter 14.)

Table 2.1 names the various data types, the namespace in which they are defined, and the acceptable range of values for each type.

Table 2.1. CTS Data Types That Supplant VB6 Data Types
Name Namespace Bytes Range
Boolean System.Boolean 2 True or False
Byte System.Byte 1 0 to 255 unsigned
Char System.Char 2 0 to 65535 unsigned
Date System.DateTime 8 January 1, 1 CE to December 31, 9999
Decimal System.Decimal 16 Approximately 7.9x10 28 with no decimal point; to 7.9 with 28 decimal points to the right of the decimal; the smallest non-zero number is 1x10 -29 (see the section on decimals for specific values)
Double System.Double 8 Approximately -1.7E308 to -4.9E-324 for negative values; 4.9E-324 to 1.7E308 for positive values (see section on double floating-point numbers for more information)
Integer System.Int32 4 -2,147,483,648 to 2,147,483,647
Long System.Int64 8 -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
Object System.Object 4 Stores any type; replaces Variant
Short System.Int16 2 -32,768 to 32,768
Single System.Single 4 Approximately -3.4E38 to -1.4E-45 for negative values; 1.4E-45 to 3.4E38 for positive values (see section on floating-point numbers for more information)
String System.String Platform-Dependent 0 to approximately 2 billion Unicode characters
User - System.ValueType Sum Platform-Dependent Sum of the size of the data types defined in the user type

Getting used to the new values of the data types will be much easier than thinking of data types as objects. As stated in the opening paragraph, data types in VB .NET can contain methods, fields, properties, and events. (Fields are private data members , usually containing an underlying value of a property. Refer to Chapter 7, "Creating Classes," for more on fields.)

For example, the following code writes the maximum value of an integer to the Output window:


Integer is the type and MaxValue is a shared attribute of Integer types. Shared members are equivalent to C++ static members or Pascal class members. (Refer to Chapter 11, "Shared Members," for more on this new idiom.) The important thing to note is that Integer is an aggregate type; although it's used like a primitive type, it's a structure and has members.

In the subsections that follow we will cover the new data types, implemented per the requirements of the Common Language Runtime, and the capabilities provided by these types.

Object Types

The Variant type originally was implemented to support COM programming. Variant types add a lot of unseen overhead to an application and sometimes lead to ambiguous code. The Variant has been replaced with the Object class in VB .NET.

Object is the name of the root class for all classes and structures in the Common Language Runtime. (The Structure construct replaces the Type construct. For more information refer to Chapter 5, "Subroutines, Functions, and Structures.") The end result is that all classes in .NET have common, basic behaviors introduced at the lowest level, and you still have a generic type if you need it. Table 2.2 contains the methods introduced in the Object class.


If you are at all familiar with Delphiimplemented in Object Pascala common ancestor named Object will sound familiar to you. This is almost exactly the name of the Object Pascal common ancestor. In Object Pascal the common ancestor is TObject.

Even though naming a class Object probably won't lend itself to clarifying the difference between an object and a class for some, having a common ancestry lends itself to implementing some pretty useful things in a development tool. Read Chapters 8, " Adding Events," and 9, "Understanding Delegates," for examples of how a common ancestry is employed in a Windows object-oriented framework.

Table 2.2. Members of the Object Class Inherited by All Classes and Structures
Member Description
Equals Tests hash code to determine equality
GetHashCode Returns mathematically derived hash code representing the object's value
GetType Returns class of type (exists to support polymorphic behavior for arguments passed as Object, as demonstrated by event handlers)
ReferenceEquals Returns a Boolean indicating whether or not two object references refer to the same object
ToString Returns a string representation of the object


It's important to note that all these member methods in no way suggest that common operators, such as =, have been supplanted by verbose methods. Common operators still exist, and you will use those operators for everyday operations. (Refer to the section on operators later in this chapter for more information.)

All the methods listed in Table 2.2 are instance methods, except the ReferenceEquals method. You need an instance of a class to invoke instance methods. ReferenceEquals is a shared method, which can be invoked using the class or an instance.


The Equals member returns a Boolean indicating whether the value of the calling instance is equivalent to the value of the argument instance. The Equals method is used to test hash code values to determine object equality. Using the prior code fragment, J.Equals(I) is True.


GetHashCode is introduced at the Object level and returns a mathematically derived number. A hash function must return the same value for disparate objects if two objects of the same type represent the same value. Hash codes are used to facilitate storing data in an abstract data type referred to as a hash table. By ensuring a random distribution of values, the hash code can be used to index elements in the hash table very quickly.


Another interesting feature in .NET is the GetHashCode method. What is that all about? I haven't found a specific reference to explain it completely, but my guess is that an equality test based on a hash code is much faster than writing all those member-wise comparisons.

 Object1.Field1 = Object2.Field2 Object1.Field2 = Object2.Field2 

Member-wise equality testing becomes tedious to write. But hashing algorithms could be written generically, relying on all objects to have a GetHashCode method.

The help documentation suggests that hash codes should be based on a constant, immutable field in a class. Thus all objects of the same type producing the same hash code are equal.


GetType returns the Type class, or metaclass, of the invoking type. The following example illustrates.

 Dim I As Integer MsgBox(I.GetType.Name) 

I.GetType returns the metaclass of the Integer type, which is an Int32 type. The Name property is of the Type class. In the example the message box would display Int32, the CLR type of an integer.

A metaclass is an instance of the class itself. This is essential to supporting Run Time Type Information (RTTI). RTTI is the name of the capability of an object-oriented framework to be able to determine the class of objects at runtime. This gives us tremendous flexibility. (An excellent example afforded by a dynamic type system is demonstrated in Chapter 6, "Reflection.")


GetTypeCode returns the type code for an object. I.GetTypeCode, where I is an Integer, returns the value 9, which is the enumerated constant TypeCode.Int32.


The ToString method returns a string representation of an object. (Calling ToString on an Integer would yield the string equivalent of that integer's value.) This method at the lowest level of the class hierarchy is useful because it ensures that all types can be represented as string values. This makes it especially easy to implement procedures such as MsgBox, passing in any type for the message.

Integral Types

There are four integral types in VB .NET: Short, Integer, Long, and Byte. Byte, Integer, and Long existed in VB6, and Short has been introduced in VB .NET. The number of bytes used to store integers and longs has been doubled in VB .NET from 16 to 32 and 32 to 64, respectively. The number of acceptable values for a type is a function of permutating the number of bits. Thus a 32-bit integer is capable of storing 2 32 possible values; split the number of possible values between negative and positive values, allow for zero, and you get a range of values from -2,147,483,648 to 2,147,483,647.

Integral types represent whole numbers only. Integers are useful for whole-number operations and indexing operations, such as those found in For... Next loops . Integer types are ValueType classes, a direct descendant of the Object type. All types are classes in .NET, although ValueType looks and feels like a native data type. Types descended from ValueType are generically referred to as value types, implying a difference between types like integer and reference types like a Button control.

The difference between reference types and value types is that reference types carry runtime type information around with them at runtime and value types do not. ValueType runtime type information is available in the metadata of the assembly (refer to Chapters 6 and 12 for more information on assemblies and metadata). When the CLR needs to treat a value type as a reference type, such as when you request type information for a value type, an operation known as boxing occurs. Boxing, named after the Intermediate Language (IL) instruction performed behind the scenes, is the process of creating a heap object and copying the value of the value type into the heap object. This allows the CLR to treat the value type as a reference type. When the reference type is no longer needed, the reverse process, called unboxing, is performed.

The differences between value types and reference types exist to support types that seem as easy to use as native types but have the benefit of objects. Fortunately all of the boxing and unboxing occurs behind the scenes seamlessly. (You can get a bird's-eye view of how .NET works by examining an executable in the ildasm.exeIL Disassemblerutility.)


Public members are members that are accessible to code outside the class or structure. Protected members are accessible to the containing class or subclasses. Refer to Chapter 7, "Creating Classes," for more on public and protected access specifiers. Access specifiers have to do with the concepts of encapsulation and information hiding.

To determine the members of an Integer, look up the CTS type Int32 and its ancestor classes in the help files. The Public shared Fields of an Integer type are the aforementioned MaxValue and MinValue. The Public shared method of an Integer is the Parse method. Public instance methods are those inherited from Object, and you can extend two protected methods, Finalize and MemberwiseClone, by deriving a new type from Object.

MinValue and MaxValue

MinValue and MaxValue in integral types are shared fields and thus are accessible without creating an instance of the type. For example, the following code refers to both shared members using the Integer type:

 Dim Test As Boolean Test = (Integer.MinValue < 100000) and (100000 < Integer.MaxValue) 

Test evaluates to True. The test would be False in VB6, but in VB .NET 100,000 is between the minimum and maximum values for Integer types.


The appearance of methods in a specific section does not imply that these methods may not exist in other classes too. Methods such as MinValue, MaxValue, and Parse are not limited to integral classes.

Shared Method: Parse

Parse is a shared method that converts the string representation of a number to its integral equivalent.

 Dim Number As String Number = "4" Debug.WriteLine(Integer.Parse(Number)) 

This example declares a variable, Number, as a String type. The string "4" is assigned to the variable, Integer.Parse(Number)uses Parsereturning the string as an Integer.

Non-Integral Types

Non-integral types are floating-point numbers, including the Single, Double, and Decimal types.

Floating-point numbers support storing a wider range of values and are useful for math operations that result in fractional numbers. The Single and Double types support a greater range of values than the decimal type, but Single and Double are subject to rounding errors. The Decimal type is better suited for financial calculations that are less tolerant of decimal rounding errors.

You can use floating-point or exponential notation when assigning values to Single or Double variables . Floating-point notation is whole. part format, for example, 3.14159. Exponential, or scientific, notation uses the mantissa E exponent format. For example, 3e2 is equivalent to 300. (Mantissa is the value part, usually normalized for a single significant digit, and the exponent is also referred to as the power multiplier .)

If you initialize a Decimal number with a value greater than the largest Long integer value, you must add the suffix D at the end of the initial value. For example, Dim Number As Decimal = 9223372036854775808D assigns roughly 9 quintillion to the variable Number (or, roughly the size of Bill Gate's fortune before the most recent stock decline).

Floating-Point Division

Floating-point numbers were modified to conform to the Institute of Electrical and Electronics Engineers (IEEE) standard for floating-precision numbers. The result is that you get some new behaviors when performing floating-point arithmetic.


The equivalent of 1/0 returns Infinity and math.Sqrt(-1) returns Not a Number (NaN) for floating-point numbers. The equivalent Integer divisions (1\0 and -1\0) would cause a DivideByZeroException.

Dividing a number by 0 results in the value Infinity being returned. For example, the following code displays a message box containing the word Infinity:

 Dim D As Double = 0 MsgBox(5 / D) 

Trying to evaluate the square root of -1 yields the value NaN (Not a Number). The following code gives an example:


Visual Basic 6 required that you write an error handler to catch problems like division by zero. In Visual Basic .NET, you can use non-integral type instance methods or operators to test for these values.

Non-Integral Type Members

There are several members for non-integral types. Table 2.3 lists and describes the members of the Single and Double types.

Table 2.3. Floating-Point Type Members
Name Description
Shared Field
Epsilon Smallest positive constant value greater than zero. (Refer to the section "Size of Types.")
MaxValue Largest possible value
MinValue Smallest possible value
NaN Symbolic constant representing a value that's Not-a-Number (NaN)
NegativeInfinity Symbolic value ( -Infinity ) representing negative infinity
PositiveInfinity Symbolic value ( Infinity ) representing positive infinity
Shared Method
IsInfinity Returns a Boolean indicating whether the argument represents Infinity (for example, Double.IsInfinity(D/0) is True)
IsNaN Returns a Boolean indicating whether the argument represents NaN
IsNegativeInfinity Test for negative infinity (for example, -1/0)
IsPositiveInfinity Test for positive infinity (for example, 1/0)
Parse Converts string argument to type of class
Instance Method
CompareTo Compares instance to argument reference, returns less than 0 if instance is less than argument; 0 if instance equals reference argument; and greater than 0 if instance is greater than reference argument

All members listed in Table 2.3 are public members of the Single and Double types.

Non-Integral Decimal Type

Decimal numbers replace the role previously played by the Currency type. Currency no longer exists in Visual Basic .NET. Members of the Decimal type are listed in Table 2.4. The list is huge, but so much effort was paid to support Decimal values (to help track Chairman Bill's fortune) that I thought the least we could do was provide a reference listing.

Table 2.4. Decimal Type Members
Name Description
Shared Field
MaxValue Largest maximum Decimal value
MinusOne Represents the number negative 1
MinValue Largest negative value
Shared Field
One Represents the number 1
Zero Represents the number 0
Shared Method
Add Add to Decimal values
Compare Compares two Decimal arguments, for example Decimal.Compare(D1, D2).
  D1 < D2 returns < 0;
  D1 = D2 returns 0, and
  D1 > D2 returns > 1.
Divide Returns Decimal result of D1 divided by D2 (for example, Decimal.Divide(D1, D2), where D1 and D2 are Decimal values)
Equals Determines whether two values are equal using Hash code
Floor Rounds a Decimal to next lower number (for example, Decimal.Floor(5.7) = 5
FromOACurrency Converts Office Automation Currency type to Decimal
GetBits Decimal represented as binary array of Int32 elements (for example, Decimal.GetBits(3).GetValue(0) = 3)
Multiply Performs decimal arithmetic on two arguments
Negate Negates the value of the Decimal argument
Parse Converts a string to a decimal (see Listing 2.4)
Round Rounds Decimal argument to the number of the decimal places indicated (for example, Decimal.Round(10.347, 2) = 10.35D)
Subtract Subtracts two Decimal arguments returning Decimal difference
ToByte Converts Decimal to 8-bit equivalent; if value is greater, Byte.MaxValue throws an exception (refer to section on Structured Exception Handling in this chapter)
ToDouble Converts Decimal to Double (see ToByte)
ToInt16 Converts Decimal to 16-bit Integer (see ToByte)
ToInt32 Converts Decimal to 32-bit Integer (see ToByte)
ToInt64 Converts Decimal to 64-bit Integer
Shared Method
ToOACurrency Converts a Decimal value to Office Automation Currency type (currency types are still supported in Microsoft Office)
ToSByte Converts Decimal to signed Byte (see ToByte)
ToSingle Converts Decimal to Single (see ToByte)
ToUInt16 Converts Decimal to 16-bit unsigned integer (see ToByte)
ToUInt32 Converts Decimal to 32-bit unsigned integer (see ToByte)
ToUInt64 Converts Decimal to 64-bit unsigned integer (See ToByte)
Truncate Returns Decimal without the fractional part
Decimal Initializes a new Decimal constructor
Instance Method
CompareTo Compares instance to argument; returns -1, 0, and 1 if instance is less than argument, equal to argument, or greater than argument, respectively

Money is important to our culture, and the many Decimal members provide us with a lot of power in managing Decimal data. As promised , Listing 2.4 demonstrates how the Parse method can be used to convert a formatted string to its Decimal equivalent.

Listing 2.4 Calling Decimal.Parse on a string containing a comma-delimited numeric value converts that string to a Decimal.
 Dim Number As String Number = "100,000,005" Debug.WriteLine(Decimal.Parse(Number)) 

Listing 2.4 writes 100000005 (one hundred million five) to the Output window. Many of the methods like Parse are commonly used in a polymorphic way. That is, you call Parse and it behaves in a meaningful way based on the type of the class. Using the same name for methods that perform semantically the same operation makes it easier to remember those method names. Just imagine if you had to memorize a unique name for the Parsebehavior for every data type. (For more on polymorphism, see Chapter 7, "Creating Classes.")

Double Types and DateTime Variables

Visual Basic .NET doesn't store date and time variables as Double precision numbers. The Common Language Specification defines a DateTime type distinct from the Double type.

Visual Basic 6 supported the following coding practice:

 Dim D As Double D = Now 

After the line D = Now, D would contain a double precision number. The whole part of the number represented the date and the fractional part of the number represented the time. Visual Basic .NET will return the error Use the ToOADate method on a Date to convert a Date type to a Double. (See the section on DateTime data types for more information.)

Char Data Type

Char is defined in System.Char. The Char type has been widened to 16 bits to support Unicode characters. The 128 ASCII characters are sufficient to support the English alphabet, but Unicode was defined to support all characters in all other languages, including the 5,000 or so Japanese Kanji characters.

The concept of a character type doesn't exist in VB6. In addition, Visual Basic .NET doesn't support the fixed-length String notation:

 Dim S As String * 1   ' no longer supported in VB.NET 

Hence a Char type fills the void nicely . Table 2.5 defines the members of the Char type.

Table 2.5. Members of the New Char Structure
Name Description
Shared Field
MaxValue Constant that represents largest char value
MinValue Constant representing smallest char value
Shared Method
CompareTo Compares instance to argument; returns -1, 0, or 1 indicating that instance is less than argument, equal to argument, or greater than argument, respectively
GetNumericValue Returns the numeric value of the Unicode character
Shared Method
GetUnicodeCategory UnicodeCategory constant Category of Unicode character grouped by enumerated
IsControl Boolean indicating whether the character is a control character
IsDigit Tests for Unicode digit category
IsLetterOrDigit Tests for Unicode letter or digit category
IsLower Tests for Unicode lowercase letter category
IsNumber Tests for Unicode decimal or hexadecimal digit category
IsPunctuation Tests for Unicode punctuation mark category
IsSeparator Tests for Unicode separator category
IsSurrogate Tests for Unicode surrogate character category
IsSymbol Tests for Unicode symbol category
IsUpper Tests for uppercase Unicode category
IsWhiteSpace Tests for whitespace category
Parse Converts value of string argument to Unicode character
ToLower Converts the Unicode character to lowercase
ToUpper Converts the Unicode character to uppercase

Declaring Char variables has the same basic syntax as declaring other types of variables. The basic syntax is

 Dim C As Char 

Refer to the upcoming section on "Variable Declarations" for more details. Shared fields and methods can be called with an instance or a class reference. The following example displays the uppercase A character in a message box:


String Type

The String type has undergone some transformations. Strings are classes like other types in Visual Basic .NET. You may no longer declare fixed-length strings as you did in VB6, but we picked up some extra goodies in return.

Strings can be about 2 billion characters long (and we now have PCs capable of storing strings that big), and strings have a tremendous number of members that make string management significantly easier.

Thus far the chapter doesn't contain a lot of code snippets for other types, but strings are so common that I have included several examples of code statements to demonstrate some of the new string capabilities listed in Table 2.6. (You will see the other examples used throughout this book. For additional examples of data types in use, refer to the sections "Variable Declarations" and "Operators" later in this chapter.)

Table 2.6. Visual Basic .NET String Class Members
Name Description
Shared Field
Empty Constant representing an empty string
Shared Method
Compare Compares two string argument objects
CompareOrdinal Compares two string arguments without considering local national language or culture
Concat Returns a new string created by appending one or more strings together
Copy Returns a new string copy of the argument string
Format Similar to C's printf; replaces format specifiers in format string with arguments provided to method
Intern Returns a reference to the string instance
IsInterned Retrieves string reference
Join Inserts separator string between each string in an array
Instance Property
Chars Returns character at position
Length Returns the string length
Instance Method
Clone Clones this string
CompareTo Compares this string to argument string
CopyTo Copies specified number of characters at offset to target index in array of Unicode characters
EndsWith Returns a Boolean indicating if this string ends with argument string
Instance Method
GetEnumerator Returns a CharEnumerator enabling you to iterate over string
IndexOf Returns index of substring
IndexofAny Returns the index of the first occurrence of any character in the argument array of characters
Insert Inserts specified string into this string at index
LastIndexOf Returns index of last instance of substring or character
LastIndexOfAny Returns the last index of any of the characters specified in the argument array
PadLeft Right-aligns string padding characters on left with spaces or specified character
PadRight Left-aligns string padding spaces or indicated character on the right
Remove Removes indicated number of characters, starting at index
Replace Replaces all occurrences of substring
Split Splits string elements into an array at delimiter ; opposite of join
StartsWith Boolean indicating if this string is prefixed with argument string
SubString Copies substring from instance string
ToCharArray Copies characters in string into Unicode character array
ToLower Returns lowercase copy of instance string
ToUpper Returns uppercase copy of instance string
Trim Trims specified characters from instance string
TrimEnd Trims specified characters from end of instance string
TrimStart Trims specified characters from start of instance string

Listing 2.5 contains various unrelated code fragments that demonstrate some of the string methods.

Listing 2.5 Examples of String class members
 1:  Sub TestStringMethods()  2:  3:      Dim S As String = _  4:      "Welcome to Valhalla Tower Material Defender"  5:      Dim T As String = S.Clone()  6:  7:      Debug.WriteLine(S.ToLower())  8:      Debug.WriteLine(S.ToUpper())  9:      Debug.WriteLine(T.EndsWith("Defender")) 10:     Debug.WriteLine(S.Chars(5)) 11:     Debug.WriteLine(String.Concat("Hello", " ", "World")) 12:     Debug.WriteLine(S.Substring(5, 10)) 13: 14:     Debug.WriteLine(String.Format(_ 15:       "Abraham Lincoln was born {0:s} ", "February 12")) 16: 17:     Dim Enumerator As CharEnumerator = S.GetEnumerator 18: 19:     While (Enumerator.MoveNext()) 20:       Debug.WriteLine(Enumerator.Current()) 21:     End While 22: 23:     Dim R() As String = {"2", "12", "1966"} 24:     MsgBox(S.Join("/", R)) 26:   End Sub 

Most of the code will make immediate sense to you. Lines 3 and 4 demonstrate the new form of combined variable declaration and initialization in VB .NET. (See the section on "Variable Declarations" for more information.) The form of member access may be a little confusing; just remember that the sequence is object . member for instance members and class . member for shared members.

Lines 17 through 21 demonstrate an Enumerator. If you've worked with iterators before, for example in C++, this code will make sense to you. Instead of subscripting the string directly, a class was written to manage iterating over the elements. The benefit of an enumerator is that the code is identical for enumerating over any type that supports working with the Enumerator class.

Line 23 may seem a little odd, too. It declares and initializes an array of strings. (Again, see the section "Variable Declarations" for more information.) You will see examples of string members used in code throughout this book.

Boolean Type

The Boolean type has gone through a couple of gyrations to get to its present state. In VB6, Boolean values used 0 for False and -1 for True as the underlying integral values. Originally VB .NET was designed to use 0 and 1 for False and True respectively.

0 and 1 are supported by the CLR, but in concession to VB6 developers, the underlying values of Booleans were converted back to 0 and -1. If you used beta 1 but skipped beta 2 of .NET, you may have missed this transmogrification. To work properly with the CLR Boolean values have to be converted internally to 0 and 1, but whenor perhaps ifyou evaluate Booleans as integers, you will get the 0 and -1 value.

To further complicate matters, Boolean operators were going to be converted to logical rather than logical and bitwise operators, and Boolean evaluations were going to be short-circuited. All these planned changes were repealed in or around April 2001. What we ended up with is Boolean behavior very similar to the behavior in VB6.

The end result is that if you always use Boolean True or False, the underlying value will have no adverse impact on your code, and Boolean values have a greater semantic meaning than do integer-as-Boolean values.

Boolean Operators

Boolean operators include And, Or, Not, and Xor. AndAlso and OrElse were added to support short-circuit evaluations in VB .NET. (See the next section for a discussion of AndAlso and OrElse operators and short circuit evaluations.)

Visual Basic .NET performs the same logical and bitwise operations with And, Or, Not, and XOR as does VB6. If the types of the operands are Boolean, the Boolean operators perform a logical evaluation. If the operands are integral, a bitwise evaluation is performed. Listing 2.6 demonstrates various logical and bitwise evaluations with the result of the operation referenced by line number in the paragraph following the code listing.

Listing 2.6 Logical and bitwise operations in VB .NET
  1:  Sub TestBooleans()  2:   3:  Dim B As Boolean  4:  B = False Or True  5:  Debug.WriteLine(B)  6:   7:  B = False Xor False  8:  Debug.WriteLine(B)  9:   10:  B = False And True  11:  Debug.WriteLine(B)  12:   13:  B = Not True  14:  Debug.WriteLine(B)  15:   16:  Dim I As Integer  17:   18:  I = 3 Or 4  19:  Debug.WriteLine(I)  20:   21:  I = 2 And 4  22:  Debug.WriteLine(I)  23:   24:  I = 3 Xor 3  25:  Debug.WriteLine(I)  26:   27:  I = Not 5  28:  Debug.WriteLine(I)  29:   30:  End Sub 

Line 5 writes True to the Output window. Line 8 writes False to the Output window; logical Xor evaluations are only True when the operands don't match. The logical test on line 10 yields False because False And anything is False. The negation of True is False; line 14 writes False to the Output window. Because line 18 is evaluating two integers, the operation will be bitwise. The last four bits for 3 are 0011, and the last four bits for 4 are 0100. 0100 Or'd with 0011 is 0111 or 7. Line 19 writes 7 to the Output window. 2 and 4 have no bits in common, so line 22 writes 0. All bits are equal on line 24. Xoring bits is exactly the way to get 0 in a bitwise evaluation. Negating 5 (having all 0s except the last four bits are 0101) yields all 1 bits in the topmost 28 bits and 1010 in the last four bits. (Remember that integers are 32 bits in VB .NET.)

Boolean Evaluations Aren't Short-Circuited

Visual Basic .NET performs complete Boolean evaluations unless you use the AndAlso and OrElse operators. A complete Boolean evaluation means that all operands are evaluated to determine the result of the statement.

Consider the statement False And anything . False And anything will always yield False. There is no practical reason to evaluate the right-hand-side (rhs) operand. Not evaluating the other operand in this context is referred to as short-circuiting evaluation. But what happens if the rhs operand is the result of a function? Further, what happens if that function does something like updating a database? The answer is that in the False And scenario, short-circuited evaluations would never update the database. The fragment that follows illustrates the scenario.

 Function UpdateDatabase() AS Boolean   ' update database   return Passed End Function If(BoolVal And UpdateDatabase()) Then 

The fragment tests the BoolVal Anded with the return value of UpdateDatabase. If BoolVal is False and Boolean evaluations were short-circuited, UpdateDatabase would never be called. Consider another example:

 Function LogIn() As Boolean   ' Login  and return connected state   return IsConnected() End Function If(LoggedIn() Or LogIn()) Then   ' Process 

In the first example, the UpdateDatabase method is always called in VB .NET. In the second example, if LoggedIn is True, an Or operator will yield True. If the loop short-circuited, LogIn() wouldn't get called. Because VB .NET was switched back to complete Boolean evaluation, LogIn() will always be called.

Writing code that depends on short-circuit or complete Boolean evaluations can lead to side effects. You can write some clever code like the LoggedIn() Or LogIn() statement, but it's best not to write too much clever code. Avoid writing code that depends on side effects related to the kind of Boolean evaluation employed, and you will sleep better.

If you intentionally want to write code that uses short-circuited evaluations in VB .NET, you can use the AndAlso and OrElse operators. AndAlso short-circuits And operations and OrElse short-circuits Or operations. For example, to short-circuit the LoggedIn() or LogIn() if conditional, replace the Or with OrElse and the statement is interpreted to mean if not logged in, then log in.

DateTime Type

Date and Time variables have been overhauled. Instead of the underlying value of a date and time variable being stored as a Double, DateTime is a type in its own right. VB6 stored the date as the whole number part and the time as the fractional part of a Double. For example, .5 was equivalent to #12:00:00 PM# in VB6.

When you want to manage date and time data in VB .NET, you will need to declare variables as DateTime types. A few methods exist for backward compatibility, but DateTime types in VB .NET are subclassed from the ValueType class and have all new methods and attributes of their own. Table 2.7 lists the public members of the DateTime type. Listing 2.7 offers some sample statements that demonstrate some of the new capabilities of DateTime types.


The .NET Framework supports overloaded operators for types, like DateTime. Operator overloading isn't supported in Visual Basic .NET; hence the help related to overloaded operators isn't applicable to VB .NET. Operator overloading is one of those idioms, along with parameterized or template methods, that give the impression of C++ being more difficult to program in.

Table 2.7. DateTime Types Are ValueType Objects in VB .NET, Not Doubles
Name Description
Shared Field
MaxValue Largest possible date; December 31, 9999 (the Y10K bug)
MinValue Smallest possible date; January 1, 1 CE (Common Era)
Shared Property
Now Current date and time
Today Today's date
UTCNow Current time on this computer expressed as UTC (Universal Coordinated Time or Greenwich Mean Time [GMT])
Shared Method
Compare Compares two date arguments; t1 < t2 returns -1; t1 = t2 returns 0; t1 > t2 returns 1
DaysInMonth Takes the year and month and returns the number of days in that month and year; year is used to account for leap year and February
FromFileTime Returns DateTime equal to operating system file timestamp
FromOADate Converts VB6, or OLE Automation Date to DateTime (for example, DateTime.FromOADate(0.5) is 12:00:00 PM)
IsLeapYear Boolean indicating whether argument year is a leap year
Shared Method
Parse Converts string date to DateTime
ParseExact Converts string argument to a DateTime using an IFormatProvider.System.Globalization. DateTimeFormatInfo implements the IFormatProvider interface
DateTime Initializes a DateTime instance
Instance Property
Date Returns the Date value of instance
Day Returns day of month of instance
DayOfWeek Instance day of the week
DayOfYear Returns the numeric day of year
Hour Returns hour value of instance
Millisecond Returns millisecond value of instance
Minute Returns minute value of instance
Month Returns month value of instance
Second Returns second value of instance
Ticks Returns number of 100-nanosecond ticks representing ticks since 1/1/0001 CE
TimeOfDay Time value for instance
Year Year value of instance
Instance Method
Add Adds TimeSpan argument to instance value
AddDays Adds specified days to instance
AddHours Adds hours to instance
AddMilliseconds Adds milliseconds to instance
AddMinutes Adds minutes to instance
AddMonths Adds months to instance
AddSeconds Adds seconds to instance
AddTicks Adds ticks to instance
AddYears Adds years to instance
Instance Method
GetDateTimeFormats Returns DateTime format String
Subtract Subtracts time of duration from instance
ToFileTime Converts DateTime to local system file time
ToLocalTime Converts UTC to local time
ToLongDateTime Converts instance date value to string
ToLongTimeString Converts instance time to String
ToOADate Converts instance to OLE Automation compatible date (Double)
ToShortDateString Converts instance date to String
ToShortTimeString Converts instance time to String
ToString Converts date and time to String
ToUniversalTime Converts instance to UTC DateTime


Prior to 1582, time was tracked using the Julian calendar. In 1582, Pope Gregory XIII created the Gregorian calendar. In later centuries the Gregorian calendar was adopted by European countries , India, China, and the American colonies.

The Gregorian calendar tracks two eras: the time before Christ ( BC , or before Christ) and the time after Christ ( AD , or anno Domini (Latin for "year of our Lord"). The generic initialization for these two eras is BCE (before common era) and CE (common era).

DateTime types track time as the number of ticks, where a tick is 100 nanoseconds, since 12:00 AM January 1, 1 CE (or AD ).

The Gregorian calendar introduced leap years, 12 months per year, and the number of days per month, including the 28 days in February and 29 in a leap year.

The new DateTime type measures time from 12:00 AM January 1, 1 CE from the Gregorian calendar in 100-nanosecond ticks. (It's interesting to note how much more closely we track time as computing power grows.) Listing 2.7 demonstrates some basic capabilities of the new DateTime class. You will see many more examples throughout the rest of the book.

Listing 2.7 Using the new DateTime type
  1:  Sub TestDateTime()  2:   3:  Debug.WriteLine(DateTime.FromOADate(0.5))  4:  Debug.WriteLine(DateTime.Parse("12:00:00 PM"))  5:  Dim Provider As New System.Globalization.DateTimeFormatInfo()  6:  Debug.WriteLine(Provider.AMDesignator())  7:  Debug.WriteLine(DateTime.ParseExact("12:42", "hh:mm", Provider))  8:   9:  Dim D As DateTime  10:  D = Now()  11:   12:  Debug.WriteLine(D.ToUniversalTime())  13:   14:  Debug.WriteLine("UTC-LocalTime=" + D.ToUniversalTime(). _  15:  Subtract.ToString())  16:   17:  Debug.WriteLine("Ticks since 12:00AM January 1, 1 CE=" _  18:  + Now().Ticks())  19:   20:  End Sub 

Line 3 converts the Double 0.5 to noon writing 12:00:00 PM . Office XP still uses VBA and consequently uses Doubles to store date and time values. On line 3, FromOADate converts an OLE Automation date to a DateTime. Line 4 converts the string to a DateTime; keep in mind that DateTime is a class rather than an instance. Line 4 demonstrates using a shared method. Line 5 creates an instance of DateTimeFormatInfo that implements the IFormatProvider interface. Line 6 uses the provider to get the AMDesignator, printing AM . Line 7 uses the Provider object as an argument to ParseExact.

Line 9 declares a DateTime variable D and line 10 initializes it to Now. You can declare and initialize variables on the same line in VB .NET (see the next section for more details.) Line 12 converts the current local time to Universal Coordinated Time (UTC). I reside in Michigan; UTC time is four hours ahead of Michigan (or EDT) time, which is demonstrated on line 14 using the Subtract method. Line 17 returns the number of ticks until the present date and time. When I ran the code the first time, the number of ticks was 631,244,136,636,562,500, or about 631 quadrillion.


Visual BasicR. NET Unleashed
Visual BasicR. NET Unleashed
Year: 2001
Pages: 222 © 2008-2017.
If you may any questions please contact us: