3.3 Data TypesThe .NET Common Language Runtime (CLR) includes the Common Type System (CTS), which defines the data types that are supported by the CLR. Thus, each of the languages in the .NET Framework (VB, C#, JScript, and Managed C++) implements a subset of a common set of data types. We say subset because, unfortunately , not all of the CTS types are implemented by VB.NET. For instance, the CTS includes some unsigned integer data types that are not implemented in VB. As an aside, it is possible to use the VB-unsupported data types in VB by direct use of the corresponding Framework Class Library class. Here is an example illustrating the ability to use the unsigned 16-bit integer data type, whose range of values is 0 to 65,535. Note the use of the ToUInt16 method of the Convert class to actually get an unsigned 16-bit integer: Dim ui As UInt16 ui = Convert.ToUInt16(65535) MsgBox(ui.ToString) Thus, the native VB data types are wrappers for the CTS data types. To illustrate , the VB Integer data type is a wrapper for the Int32 structure that is part of the .NET Framework's System namespace. One of the members of the Int32 structure is MaxValue, which returns the maximum value allowed for this data type. Thus, even though MaxValue is not officially part of VB.NET (nor is it mentioned in the VB documentation), we can write: Dim i As Integer MsgBox(i.Maxvalue) ' Displays 2147483647 3.3.1 Value and Reference TypesThe types defined in the CTS fall into three categories:
However, pointer types are not implemented in VB, so we will not discuss these types. The difference between value and reference types is how variables of the corresponding type represent that type. When a value-type variable is defined, as in: Dim int As Integer = 5 a memory location is set aside to hold the actual data (in this case the number 5). In contrast, when a reference-type variable is defined, as in: Dim obj As New CEmployee the VB compiler creates the object in memory, but then sets the variable obj to a 4-byte memory location that contains the address of the object. In short, value-type variables contain the data, whereas reference-type variables point to the data. The distinction between value type and reference type has several consequences, one of which is in the way assignments work. To illustrate, consider the following class, which has a single property: Public Class MyClass Public Age As Short End Class and the structure MyStruct , also with a single property: Structure MyStruct Public Age As Short End Structure Classes are reference types, whereas structures are value types. Now consider the following code, which is thoroughly commented: ' Declare two class variables and two structure variables. Dim objRef1 As MyClass Dim objRef2 As MyClass Dim objValue1 As MyStruct Dim objValue2 As MyStruct ' Instance the class. objRef1 = New MyClass( ) ' Set the Age property to 20. objRef1.Age = 20 ' Set the second variable to the first variable. ' This is an equating of object *references* because ' classes are reference types. objRef2 = objRef1 ' Set the Age property of objRef2 to 30. objRef2.Age = 30 ' Check the values of the Age property. Debug.WriteLine(objRef1.Age) Debug.WriteLine(objRef2.Age) ' Do the same thing with the structure ' Instance the structure. objValue1 = New MyStruct( ) ' Set the Age property to 20. objValue1.Age = 20 ' Set the second variable to the first variable. ' This is an equating of object *values* because ' structures are value types. objValue2 = objValue1 ' Set the Age property of objValue2 to 30. objValue2.Age = 30 ' Check the values of the Age property. Debug.Writeline(objValue1.Age) Debug.Writeline(objValue2.Age) Now, the output is: 30 30 20 30 To understand what is happening, we need to realize that the reference assignment: objRef2 = objRef1 sets both variables to the same value. But that value is the address of the object, and so both variables point to the same object. Hence, when we change the Age property using the second variable, this change is also reflected in the first variable. On the other hand, the value assignment: objValue2 = objValue1 causes a second structure to be created, setting the new structure's properties to the same value as the original structure. Thus, changing one structure's Age property does not affect the other structure's Age property. Note that the VB Array type is also a reference type. To illustrate, consider the following code: Dim iArray1( ) As Integer = {1, 2, 3} Dim iArray2( ) As Integer iArray2 = iArray1 iArray1(0) = 100 msgbox(iArray2(0)) The message box displays 100, indicating that both array variables point to the same array. The String data type is a reference type, implemented by the String class. However, it has some characteristics of a value type. To illustrate, consider the following code: Dim s1, s2 As String s1 = "String 1" s2 = s1 s2 = "String 2" MsgBox(s1) Since this is a reference type, we would expect the last line to produce the message "String 2" , but instead we get "String 1" . The reason can be found in Microsoft's documentation:
Thus, the code: s2 = s1 points s2 to the same string as s1, as is usual with reference types. Then the attempt to modify the string in the code: s2 = "String 2" does not produce the expected result because strings are immutable. Instead, we get a new string pointed to by s2, while s1 retains its value. The following code supports this conclusion: Dim s1, s2 As String s1 = "String 1" ' s2 poitns to same string as s1 s2 = s1 ' Show s2 before any changes to the string MsgBox(s2) ' Displays "String1" ' Change the string s2 = "String 2" ' Set s1 to Nothing s1 = Nothing ' Now s1 is nothing and displays accordingly MsgBox(s1) ' Displays nothing ' s2 is a new string MsgBox(s2) ' Displays "String 2" Enjoy! 3.3.2 VB Data Types: A SummaryThe following lists the data types supported by VB.NET, along with their underlying .NET type, storage requirements, and range of values:
Note that the CTS data types are either structures (which are value types) or classes (which are reference types) and are located within the .NET System namespace. 3.3.3 Simple Data Types in Visual BasicIn this section, we discuss data types in general and VB.NET data types in particular. Simple data types can be classified into groups as follows . Note that these groups are not mutually exclusive:
Let us consider the Visual Basic .NET data types individually. 3.3.3.1 Boolean data typeThe Boolean is a 16-bit data type that can only represent two values: True and False . The VB keywords True and False are used to assign these values to a Boolean variable. When a numeric value is converted to Boolean, any nonzero value is converted to True , and zero is converted to False . In the other direction, False is converted to zero, and True is converted to -1. (Incidentally, in C, C#, and C++, True is converted to 1. This change was made in Beta 1 of VB.NET to bring it in line with the other languages, but was subsequently changed back in Beta 2.) The underlying .NET data type for Boolean is System.Boolean. 3.3.3.2 Byte data typeThe Byte data type is an 8-bit unsigned data type whose range is the set of integers from 0 to 255. According to the documentation, the Byte data type "is used for containing binary data." Since ordinary arithmetic operations can be used with Byte variables, the data type is, in this sense, an integer data type. Also, there do not appear to be any special operators, such as shift operators, that would give the type a "binary data" flavor. Oh well. The underlying .NET data type for Byte is System.Byte. 3.3.3.3 Char data typeThe Char data type is a 16-bit character data type with a character code ranging from 0 to 65,535, which represent a single Unicode character. As a data type, Char is new to VB.NET; there was no equivalent in previous versions of Visual Basic. It is important not to confuse the Char and String data types. (We discuss this data type in Section 3.3.3.12.) A string consisting of a single character is not the same as a Char. To illustrate, consider defining a new string and initializing it to a sequence consisting of a repeated single character, for example, "AAAAA." In earlier versions of VB, this was done as follows: Dim s As String s = String$(5, "A") In VB.NET, this is done using the String class constructor, which has the syntax: Dim variable As New String(Character, Integer) If we turn strict type checking on with the Option Strict On statement, the code: Dim s As New String("A",5) produces the error message, "Option Strict disallows implicit conversions from String to Char." To get a Char, we must append a c to the end of the string literal. Thus, the following works: Dim s As New String("A"c, 5) The underlying .NET data type for Char is System.Char. 3.3.3.4 Date data typeDate values are stored as IEEE 64-bit long integers that can represent dates in the range January 1, 0001 to December 31, 9999 (which should be plenty), and times from 0:00:00 to 23:59:59. Literal strings must be enclosed in number signs (#) to be recognized as dates. The VB.NET compiler changes date formats automatically. For instance, if we enter the code: Dim d As Date d = #November 9, 1948# Msgbox(d) the compiler changes the second line to: d = #11/9/1948# or whatever the regional settings on the host system dictate . The .NET equivalent of Date is System.DateTime. 3.3.3.5 Decimal data typeValues of the Decimal data type are stored as 96-bit (12-byte) signed integers, along with an internal scale factor ranging from 0 to 28, which is applied automatically when we set a value for a Decimal variable. This allows us to enter values from a number of different ranges. For instance, we can use integers (no decimal part) in the range:
in which case the scale factor is set to 0. On the other extreme, we can use values in the range:
on the negative side, or:
on the positive side. In this case, the scale factor is set to 28. To write a literal Decimal, append a D , as in: 123456.789D The type identifier for Decimal is the symbol @ , as in: Dim dec@ The underlying .NET data type for Decimal is System.Decimal. This class has some useful members, such as MaxValue and MinValue, which give the maximum and minimum values of the decimal type. By the way, in previous versions of VB, the Decimal existed only as a Variant data subtype ” there were no variables of type Decimal. 3.3.3.6 Double data typeValues of type Double are IEEE 64-bit (8-byte) floating-point numbers with the range:
on the negative side, and:
on the positive side. To write a literal Double, we must append an R , as in: 12345.678R The type identifier for a Double is # , as in: Dim dbl# The underlying .NET data type for Double is System.Double. 3.3.3.7 Integer data typeThe Integer data type is a 32-bit data type that stores signed integers ranging from:
or:
Note that this is the native word size on a 32-bit processor, and so the Integer data type provides superior performance as compared to integer data types of other sizes. Note also that this data type size is new for VB.NET. In VB 6 and earlier, the Integer data type was a 16-bit data type. To define a literal Integer, append an I , as in: 123I The Integer type identifier is the percent sign (%), as in: Dim int% The underlying .NET data type for Integer is System.Int32. 3.3.3.8 Long data typeThe Long data type is a 64-bit integer data type that stores signed integers ranging from:
or:
Note that this data type size is new for VB.NET. In VB 6 and earlier, the Long data type was a 32-bit data type. To define a literal Long, append an L , as in: 123L The Long type identifier is the ampersand sign ( & ), as in: Dim lng& The underlying .NET data type for Long is System.Int64. 3.3.3.9 Object data typeThe Object data type is a pointer data type. That is, a value of type Object is an address that references the object in memory. In VB.NET, the Object data type is the universal data type; an Object variable can refer to (point to) data of any other data type. For instance, the following code places a Long value in an Object variable: Dim obj As Object obj = 123L The underlying .NET data type for Object is System.Object. It is worth noting that when we use variables of type Object, we do pay a performance penalty because VB.NET cannot bind the object's method invocations to the actual method code until runtime. This is referred to as late binding . On the other hand, declaring variables of a specific object type allows early binding at compile time, which is much more efficient. Thus, code such as: Dim obj As Object . . . obj.AMethod is much less efficient than: Dim obj As System.Data.DataSet . . . obj.AMethod We revisit this issue in more detail later in this chapter. As we have seen, the Object data type is universal. Just as in VB 6, in which you can use the VarType function to determine the data subtype of a Variant, in VB.NET you can use the VarType function to determine the data subtype of an object. In addition, the Object class in the Framework Class Library's System namespace has a method named GetType that returns an object of type Type. Thus, if obj is a variable of type Object, then the code: obj.GetType returns a Type object. In turn, the Type class, which is also a member of the Framework Class Library's System namespace, has two methods that return information about the subtype of the object:
For reference, the following code generates the values in Table 3-1: Dim obj As Object obj = ??? debug.write(obj.GetType.ToString) Debug.Write(TypeName(obj)) debug.writeline(Type.GetTypeCode(obj.GetType)) Table 3-1. Values of ToString and GetTypeCode
3.3.3.10 Short data typeThe Short data type is a 16-bit integer data type that stores signed integers ranging from:
or:
Note that in earlier versions of Visual Basic, the Short data type is called the Integer data type. To define a literal Short, append an S , as in: 123S The underlying .NET data type for Short is System.Int16. 3.3.3.11 Single data typeValues of type Single are IEEE 32-bit (4-byte) floating-point numbers with the range:
on the negative side, and:
on the positive side. To write a literal Single, we must append an F (for floating point), as in: 12345.678F The type identifier for a Single is an exclamation point ( ! ), as in: Dim sng! The underlying .NET data type for Single is System.Single. 3.3.3.12 String data typeThe String data type represents Unicode strings of up to approximately 2 billion characters. The type identifier for the string data type is a dollar sign ( $ ). The underlying .NET data type for this type is System.String. To create a new string, we can declare a variable and assign it a string as follows: Dim sName As String sName = "Donna" or equivalently, in one statement: Dim sName As String = "Donna" The type identifier for a String is a dollar sign ( $ ), as in: Dim str$ 3.3.3.13 Structure data type: user-defined typesIn VB.NET, the Structure type is a powerful data type that has many properties in common with classes. To declare a structure, we use the Structure statement, whose syntax is: [PublicPrivateFriend] Structure StructureName Nonmethod member declarations Method member declarations End Structure The members of a structure can be variables, properties, methods, or events. Note, however, that each member must be declared with an access modifier: Public (or Dim ), Private , or Friend . The simplest and most common use of structures is to encapsulate related variables. For instance, we might define a structure as follows: Structure strPerson Public Name As String Public Address As String Public City As String Public State As String Public Zip As String Public Age As Short End Structure To define a variable of type strPerson , we write (as usual): Dim APerson As strPerson To access a member of a structure, we use the dot syntax, as in: APerson.Name = "Beethoven" Note that structure members can be other structures or other objects. Structures can also be passed as arguments to functions, or as the return type of a function. As mentioned, structures are similar to classes. For instance, consider the following structure: Structure strTest ' A public nonmethod member Public Name As String ' A private member variable Private msProperty As String ' A public method member Public Sub AMethod( ) Msgbox("Structure method. Property is: " & msProperty) End Sub ' A public property member Public Property AProperty( ) As String Get AProperty = msProperty End Get Set msProperty = Value End Set End Property End Structure Now we can set the structure's property and invoke its method as follows: Dim str As strTest str.AProperty = "Donna" str.AMethod( ) Although structures are similar to classes, they do not support the following class features:
For a reference to the object-oriented terminology, see Chapter 4. 3.3.4 Data Type ConversionThe process of converting a value of one data type to another is called conversion or casting . A cast operator can be applied to a literal value or to a variable of a given type. For instance, we have: Dim lng As Long Dim int As Integer = 6 ' Cast an Integer variable to a Long lng = CLng(Int) ' Cast a literal integer to a Long lng = CLng(12) A cast can be widening or narrowing. A widening cast is one in which the conversion is to a target data type that can accommodate all values in the source data type, such as casting from Short to Integer or Integer to Double. In such a case, no data is ever lost, and the cast will not generate an error. A narrowing cast is one in which the target data type cannot accommodate all values in the source data type. In this case, data may be lost, and the cast may not succeed. Under VB.NET, conversions are made in two ways: implicitly and explicitly. An implicit conversion is done by the compiler when circumstances warrant it (and if it is legal). For instance, if we write: Dim lng As Long lng = 54 then the compiler casts the Integer 54 as a Long. The type of implicit conversion that the compiler will do depends in part on the setting of the Option Strict value. For instance, if Option Strict is On, only widening casts can be implicit; so then the following code: Dim b As Boolean b = "True" generates a type conversion error, whereas if we add the line: Option Strict Off to the beginning of the module, then the previous code executes without error. Explicit conversion requires explicitly calling a conversion function (or cast operator). The type conversion functions supported by VB.NET all have the form: C name ( expression ) where expression is an expression that is in the range of the target data type. Specifically, we have the following conversion functions:
|