You need to convert between any two of
the following types: bool
,
char
, sbyte
,
byte
, short
,
ushort
, int
,
uint
, long
,
ulong
, float
,
double
, decimal
,
DateTime
, and string
. Different
languages sometimes handle specific conversions differently; you need
a way to perform these conversions in a consistent manner across all
.NET languages. One situation where this recipe is needed is when
VB.NET and C# components communicate within the same application.
Different languages sometimes handle casting of larger numeric types
to smaller numeric types differently—these types of casts are
called narrowing conversions. For example
consider the following Visual Basic .NET (VB.NET) code which casts a
Single
to an Integer
:
' Visual Basic .NET Code: Dim initialValue As Single Dim finalValue As Integer initialValue = 13.499 finalValue = CInt(initialValue) Console.WriteLine(finalValue.ToString( )) initialValue = 13.5 finalValue = CInt(initialValue) Console.WriteLine(finalValue.ToString( )) initialValue = 13.501 finalValue = CInt(initialValue) Console.WriteLine(finalValue.ToString( ))
This code outputs the following:
13 14 14
Notice that using the CInt
cast in VB.NET uses the
fractional portion of the number to round the resulting number.
Now let’s convert this code to C# using the explicit casting operator:
// C# Code: float initialValue = 0; int finalValue = 0; initialValue = (float)13.499; finalValue = (int)initialValue; Console.WriteLine(finalValue.ToString( )); initialValue = (float)13.5; finalValue = (int)initialValue; Console.WriteLine(finalValue.ToString( )); initialValue = (float)13.501; finalValue = (int)initialValue; Console.WriteLine(finalValue.ToString( ));
This code outputs the following:
13 13 13
Notice that the resulting value was not rounded. Instead, the C# casting operator simply truncates the fractional portion of the number.
Consistently casting numeric types in any language can be done
through the static methods on the Convert
class.
The previous C# code can be converted to use the
ToInt32
method:
// C# Code: finalValue = Convert.ToInt32((float)13.449); Console.WriteLine(finalValue.ToString( )); finalValue = Convert.ToInt32((float)13.5); Console.WriteLine(finalValue.ToString( )); finalValue = Convert.ToInt32((float)13.501); Console.WriteLine(finalValue.ToString( ));
This code outputs the following:
13 14 14
All
conversions performed using methods on the Convert
class are considered to be in a checked context in C#. VB.NET does
not have the concept of a checked or unchecked context, so all
conversions are considered to be in a checked context—an
unchecked context cannot be created in VB.NET. An
OverflowException
will be thrown in a checked context
when a narrowing conversion results in a loss of information. This
exception is never thrown in an unchecked context when a narrowing
conversion results in a loss of information.
The various conversion methods are listed in Table 3-2.
Table 3-2. Conversion methods on the Convert class
Method |
Use |
---|---|
Convert a type to a | |
Convert a type to a | |
Convert a type to a | |
Convert a type to a | |
Convert a type to a | |
Convert a type to an | |
Convert a type to a | |
Convert a type to a | |
Convert a type to a | |
Convert a type to a | |
Convert a type to a | |
Convert a type to an | |
Convert a type to a | |
Convert a type to a | |
Convert a type to a |
Converting between any of the data types listed in Table 3-2 is a simple matter. All of the listed methods
are static and exist on the Convert
class.
Converting one type to another is performed by first choosing the
correct method on the Convert
class. This method
will be named after the type you are converting to (e.g., if you are
converting to a char
type, the method name would
be ToChar
). Next, you need to pass the type that
will be casted as the parameter to the Convert
method. Finally, set a variable of the resultant cast type equal to
the return value of the Convert
method. The
following code converts the value in variable
Source
—defined as a short
that contains a number between 0 and 9—to a
char
type. This char
value is
then returned by the Convert
method and assigned
to the variable destination
. The variable
destination
must be defined as a
char
:
destination = Convert.ToChar(source);
There are cases in which conversions will do nothing. Converting from
one type to that same type will do nothing except return a result
that is equivalent to the source variable’s value.
Take, for example, using the Convert.ToInt32
method to convert a source variable of type Int32
to a destination variable of type Int32
. This
method takes the value obtained from the source variable and places
it in the destination variable.
Some conversions cause exceptions to occur because there is no clear
way of converting between the two types; these attempted conversions
are listed in Table 3-3. Because some conversions
might or might not throw an exception—such as converting from
an sbyte
to a byte
—it is
good programming practice to enclose the static conversion method
within a try/catch
block. The following code wraps
a conversion between numeric types in a try/catch
block:
try { finalValue = Convert.ToInt32(SomeFloat); } catch(OverflowException oe) { // Handle narrowing conversions that result in a loss // of information here. } catch(InvalidCastException ice) { // Handle casts that cannot be performed here. }
The following code wraps a conversion from a
string
type to an Int32
in a
try/catch
block:
try { finalValue = Convert.ToInt32(SomeString); } catch(OverflowException oe) { // Handle narrowing conversions that result in a loss // of information here. } catch(ArgumentException ae) { // Handle nulls passed into the Convert method here. } catch(FormatException fe) { // Handle attempts to convert a string that does not contain // a value that can be converted to the destination type here. } catch(Exception e) { // Handle all other exceptions here. }
Table 3-3. Cases where a Source to Destination type conversion throws an exception
Notice that the string
type can be converted to any type, and that any type may be converted
to a string
type—assuming that the source
string
is not null
and conforms
to the destination type’s range.
The most insidious problems can occur when a larger type is converted
to a smaller type in an unchecked context; the potential exists for
information to be lost. Code runs in an unchecked context if the
conversion is contained in an unchecked
block or
if the /checked
compiler option is set to
false
(by default, this compiler option is set to
false
in both debug
and
release
builds). An example of code contained in
an unchecked
block is as follows:
short destination = 0; int source = Int32.MaxValue; unchecked(destination = (short)source);
or:
unchecked { short destination = 0; int source = Int32.MaxValue; destination = (short)source; }
A checked context is when the conversion is contained in a
checked
block or if the
/checked
compiler option is set to
true
. An example of code contained in a
checked
block is as follows:
short destination = 0; int source = Int32.MaxValue; checked(destination =(short)source);
or:
checked { short destination = 0; int source = Int32.MaxValue; destination = (short)source; }
This code throws an OverflowException
exception if
any loss of information would occur. This allows the application to
be notified of the overflow condition and to handle it properly.
The Convert
method is always considered to operate
in a checked context, even when no other type of checked context
wraps the code performing the conversion.