Lesson 1: Using Data Types
The Microsoft .NET Framework provides a robust system of primitive types to store and represent data in your application. Data primitives represent integer numbers, floating-point numbers, Boolean values, characters, and strings. This type system enforces type-safety so that implicit casts occur only when no loss of data is possible. Explicit conversions can be performed in situations that might cause a loss of data. The .NET data types contain functionality to perform a variety of type-related conversions and tasks.
After this lesson, you will be able to
Describe the data types provided by the .NET Framework
Explain how to perform implicit and explicit conversions between types
Describe the functionality provided by types of the .NET Framework
Describe string manipulation functions with the String class methods
Estimated lesson time: 30 minutes
The .NET Framework provides an extensive system of types that allow you to store, manipulate, and pass values between members of your application. The .NET languages are strongly typed. Strongly typed means that objects of one type cannot be freely exchanged with objects of a different type. A call will fail if method and property parameters are not the appropriate type. Implicit and explicit conversions allow you to convert data types when necessary. Such conversions are possible because all types in the .NET Framework derive from Object, the base type of all classes and structures.
The .NET Data Types
The .NET data types store your data. They are value types and can be broken down into the following subcategories: Integer types, floating-point types, the Boolean type, and the Char type. Two built-in reference types, the String type and the Object type, are an integral part of your application.
Integer Types
The .NET Framework provides a variety of Integer types. Table 3.1 summarizes these types and lists their corresponding Visual Basic .NET and Visual C# types.
Type | Visual C# Name | Visual Basic .NET Name | Description | Range |
System.Byte | byte | Byte | 8-bit unsigned integer | 0 to 255 |
System.Int16 | short | Short | 16-bit signed integer | -32768 to 32767 |
System.Int32 | int | Integer | 32-bit signed integer | -231 to 231-1 |
System.Int64 | long | Long | 64-bit signed integer | -263 to 263-1 |
System.SByte | sbyte | (Not implemented) | 8-bit signed integer | -128 to 127 |
System.UInt16 | ushort | (Not implemented) | 16-bit unsigned integer | 0 to 65535 |
System.UInt32 | uint | (Not implemented) | 32-bit unsigned integer | 0 to 232-1 |
System.UInt64 | ulong | (Not implemented) | 64-bit unsigned integer | 0 to 264-1 |
You can assign values to the Integer types using either decimal or hexadecimal notation. To use hexadecimal notation in an integer literal, it should be prefixed with &H for Visual Basic .NET and 0x for Visual C#. For example:
Visual Basic .NET
Dim myInteger As Integer myInteger = &H32EF
Visual C#
int myInteger; myInteger = 0x32EF;
Floating-Point Types
Three floating-point types can be used to represent numbers that have a fractional component. They are summarized in Table 3.2.
Type | Visual C# Name | Visual Basic .NET Name | Description | Precision | Range (Approximate) |
System.Single | float | Single | 32-bit floating-point variable | 7 significant digits | +/- 1.4 x 10-45 to +/-3.4 x 1038 |
System.Double | double | Double floating-point variable | 64-bit significant digits | 15 16 | +/- 5.0 x 10-324 to +/-1.7 x 10308 |
System.Decimal | decimal | Decimal floating-point variable | 128-bit digits | 28 significant | +/- 1.0 x 10-28 to +/- 7.9 x 1028 |
The System.Single type is appropriate for floating-point calculations that require a lower degree of precision than normal floating-point operations. It provides seven significant digits of precision. For a much greater degree of precision, you can use the System.Double type, which also has the ability to handle vastly larger values. The System.Decimal type is specifically designed to facilitate financial calculations and is an ultra-high-precision variable. Although it cannot hold values as great as System.Double, it has a much higher level of precision, providing 28 significant digits.
Non-Numeric Types
Four additional types do not represent numbers: System.Boolean, System.Char, System.String, and System.Object.
System.Boolean
The System.Boolean type is used to represent a value that is either true or false. It is called Boolean in Visual Basic .NET, and bool in Visual C#. The values that are valid for Boolean variables are True and False (Visual Basic .NET) or true and false (Visual C#).
System.Char
The System.Char type represents a single instance of a 16-bit Unicode character. It is called Char in Visual Basic .NET and char in Visual C#. You can assign a character literal to a variable of this type by enclosing the literal in double quotes using the suffix c (Visual Basic .NET) or in single quotes (Visual C#), as follows:
Visual Basic .NET
Dim myChar As Char myChar = "W"c
Visual C#
char myChar; myChar = 'W';
You can also use the numeric value of the Unicode character to make the assignment to a Char variable. In Visual Basic .NET, you must use the Chr or ChrW function to make the assignment. In Visual C#, you can provide a four-digit hexadecimal Unicode character. Examples follow:
Visual Basic .NET
Dim myChar As Char myChar = Chr(521)
Visual C#
char myChar; myChar = '\u01fe';
System.String
The System.String type is a reference type that represents a series of Char data types. In everyday terms, a string can represent a word, a paragraph, a key value, or any other string of characters. In Visual Basic .NET, this type is called String, and in Visual C#, it is called string. You can assign string literals to a string variable by enclosing them in double quotes, as follows:
Visual Basic .NET
Dim myString As String myString = "This is a String! Wow!"
Visual C#
string myString; myString = "This is a String! Wow!";
The String class contains a good deal of built-in functionality, which is discussed later in this lesson.
System.Object
The Object type is the supertype of all types in the .NET Framework. Every type, whether value type or reference type, derives from System.Object. In Visual Basic .NET, it is called Object, and in Visual C#, it is called object. You can assign any object or value to an object variable as follows:
Visual Basic .NET
Dim myObject As Object myObject = 543 myObject = New System.Windows.Forms.Form()
Visual C#
object myObject; myObject = 543; myObject = new System.Windows.Forms.Form();
If an object of a particular type is stored in an Object variable, it must be explicitly converted back to that type to access any of its inherent functionality.
Converting Types
At times, you will need to convert data from one type to another. Data can be converted in two ways: implicitly, which means that the conversion is performed automatically, and explicitly, which means that you must specifically ask for the conversion to be performed.
Implicit Conversions
Implicit conversions between types are performed whenever the conversion can occur without the loss of data. For example:
Visual Basic .NET
Dim anInteger As Integer = 100 Dim aLong As Long ' Because a long can be assigned to every possible value of integer, ' there is no chance of losing data aLong = anInteger
Visual C#
int anInteger = 100; long aLong; // Because a long can be assigned to every possible value of integer, // there is no chance of losing data aLong = anInteger;
If a type can be implicitly converted to another type, you can use the first type anywhere that the second is required without special syntax. For example, in method calls:
Visual Basic .NET
' This example assumes that the TakesADouble method requires a ' Double as a parameter Dim I As Integer = 100 ' I is implicitly converted to Double and used in the method call TakesADouble(I)
Visual C#
// This example assumes that the TakesAdouble method requires a // double as a parameter int I = 100; // I is implicitly converted to double and used in the method call TakesAdouble(I);
Table 3.3 shows the implicit conversions that are supported by Visual Basic .NET and Visual C#.
From | To |
Byte (Visual Basic .NET) byte (Visual C#) | Short, Integer, Long, Single, Double, Decimal short, ushort, int, uint, long, ulong, float, double, decimal |
Short short | Integer, Long, Single, Double, Decimal int, long, float, double, decimal |
Integer int | Long, Single, Double, Decimal long, float, double, decimal |
Long long | Single, Double, Decimal float, double, decimal |
Single float | Double double |
Char char | Integer, Long, Single, Double, Decimal int, uint, long, ulong, float, double, decimal |
sbyte (Visual C# only) | short, int, long, float, double, decimal |
ushort (Visual C# only) | int, uint, long, ulong, float, double, decimal |
uint (Visual C# only) | long, ulong, float, double, decimal |
ulong (Visual C# only) | float, double, decimal |
Explicit Conversions
When performing a conversion where types cannot be implicitly converted, you must explicitly convert the types. This conversion is called a cast. Explicit conversions are accomplished in Visual Basic .NET using the CType function and using a special syntax in Visual C#. Examples follow:
Visual Basic .NET
Dim aLong As Long = 1000 Dim anInteger As Integer anInteger = CType(aLong, Integer)
Visual C#
long aLong = 1000; int anInteger; anInteger = (int)aLong;
Explicit conversions can be risky. In the preceding example, the conversion was accomplished without any difficulty because both a Long and an Integer can hold a value of 1000. However, consider the following example:
Visual Basic .NET
Dim anInteger As Integer = 100000 Dim aShort As Short aShort = CType(anInteger, Short)
Visual C#
int anInteger = 100000; short aShort; aShort = (short)anInteger;
The code in this example will compile and execute without raising an error. However, when you examine the value of aShort, you find that it contains -31072. Because the maximum value of aShort is smaller than the value that you attempted to convert, the conversion could not be performed and a different value was returned.
NOTE
Because explicit casts are inherently dangerous, you should use them only when absolutely necessary, and you should always provide a system for handling failed casts and handle any exceptions that might be thrown. Exception handling will be discussed in Chapter 5.
Option Strict in Visual Basic .NET
Visual Basic .NET provides a programming option called Option Strict. When Option Strict is on, strong typing is enforced and only conversions that can be performed without loss of data are allowed. When Option Strict is off, however, strong typing is not enforced and all conversions are performed implicitly. The default setting for Visual Basic .NET is Option Strict Off. To set Option Strict On, use the Option keyword in the first line of your code file. For example:
Visual Basic .NET
Option Strict On
The primary purpose of Option Strict Off is backward compatibility with previous versions of Visual Basic. Whenever possible, you should program with Option Strict On. This will allow you to catch many errors during compilation that would be extremely difficult to track down at run time.
To convert types
If the conversion is of a type where no data can be lost, it will be performed implicitly and no explicit declaration is needed.
If the conversion potentially could cause a loss of data, you must perform an explicit cast to convert your types. Use the CType function in Visual Basic .NET, and the cast syntax function in Visual C#.
Using Data Type Functionality
All data types have built-in functionality. At the very least, they all support the following four methods:
Determines whether two instances are equal
Serves as a hash function for a particular type
Returns the type object for the current instance
Returns a human-readable form of the object
You have seen that the data types are small. How, then, are they able to implement these methods?
Boxing
The secret is called boxing. Boxing is the implicit conversion of value types to reference types. All classes and types derive from Object, and each of these four methods is a method of the Object class. Because each class derives from Object, each class can be implicitly converted to that type. When you call one of these methods, the Common Language Runtime creates a temporary reference for your value type variable and allows you to treat it as a reference type.
You also can box value types manually. To do this, you simply assign your value to a variable of the Object type. An example follows:
Visual Basic .NET
Dim I As Integer = 100 Dim O As Object O = I
Visual C#
int I = 100; object O; O = I;
Unboxing is the conversion of a boxed variable back to a value type. To unbox a variable, you must perform an explicit cast on the object to convert it to the appropriate type. Only objects that have been boxed can be unboxed.
Data Type Member Methods
Data types also have methods that do not derive from Object. These methods usually involve functionality specific to the type. For example, in Chapter 2, you were introduced to some of the comparison functions of the Char data type. Although a detailed discussion of all these methods is beyond the scope of this lesson, summaries of some of the more useful methods are provided.
Parse
All of the value data types implement a Parse method. Parse is used to create a numeric value from a string. The Parse method is extremely useful when developing user interfaces. Controls that accept user input, such as TextBox, do so in the form of a string. The Parse method can be used to convert that string to usable data. Note that if a string cannot be read as a numeric value, an error will result. In all implementations, Parse is a static (Shared) method and must be called from the type object rather than from an instance.
To convert a string to a numeric data type
Call the Parse method of that data type on that method. An example follows:
Visual Basic .NET
Dim I As Integer Dim S As String S = "1234" ' I = 1234 I = Integer.Parse(S)
Visual C#
int I; string S; S = "1234"; // I = 1234 I = int.Parse(S);
String Functions
String manipulations are keenly important for many applications converting strings to display formats, for instance, or extracting substrings from existing strings. The String class exposes a variety of member methods for the manipulation of strings. Tables 3.4 and 3.5 summarize some of these methods. The tables are divided into instance methods, which return a string based on the instance of the string they are called from, and static methods, which must be called from the String type.
Name | Description |
String.Insert | Inserts a specified string into the current instance |
String.PadLeft, String.PadRight | Adds characters to the left and right of the string, respectively |
String.Remove | Deletes a specified number of characters from the string, beginning at a specified character |
String.Replace | Replaces all occurrences of a specified character in the string with another specified character |
String.Split | Returns an array of substrings that are delimited by a specified character |
String.Substring | Returns a substring from the specified instance |
String.ToCharArray | Returns an array of the characters that make up the string |
String.ToLower, String.ToUpper | Returns the string converted to all lowercase or all uppercase, respectively |
String.TrimEnd, String.TrimStart, String.Trim | Removes trailing, leading, or both characters from the string, respectively |
Name | Description |
String.Compare | Compares two specified string objects |
String.Concat | Returns a string that is the result of the concatenation of two or more strings |
String.Format | Returns a string that has been formatted according to a specified format |
String.Join | Returns a string that is the result of the concatenation of a specified array of strings, with a specified separation string between each member of the array |
Lesson Summary
The .NET Framework provides a robust, strongly typed data system. Different types represent integer numbers, floating-point numbers, Boolean values, characters, and strings.
Conversion between types can take one of two forms:
Implicit conversions, which are performed automatically by the Common Language Runtime. Implicit conversions can only occur where there is no possible loss of data, such as a conversion from a lower precision type to a higher precision type.
Explicit conversions are performed explicitly in code and can lead to the loss of data. Explicit conversions should be undertaken with caution.
In Visual Basic .NET, Option Strict On enables type checking at design time and prevents type mismatch bugs that could be time-consuming to find otherwise. Whenever possible, you should develop with Option Strict On.
Boxing allows you to treat a value type the same as a reference type. Unboxing converts a boxed reference type back to a value type.
The .NET types provide built-in functionality specific to the type. The Parse method is implemented by all the built-in value types and is useful for converting strings to value types. The String class exposes several useful functions that allow you to easily manipulate strings.