Recipe3.12.Converting Between Simple Types in a Language-Agnostic Manner


Recipe 3.12. Converting Between Simple Types in a Language-Agnostic Manner

Problem

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 in which this recipe is needed is when VB.NET and C# components communicate within the same application.

Solution

Different languages sometimes handle casting of larger numeric types to smaller numeric types differentlythese 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 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 

Discussion

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 contextan 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

ToBoolean

Convert a type to a bool.

ToChar

Convert a type to a char.

ToString

Convert a type to a string.

ToDateTime

Convert a type to a DateTime.

ToInt16

Convert a type to a short.

ToInt32

Convert a type to an int.

ToInt64

Convert a type to a long.

ToUInt16

Convert a type to a ushort.

ToUInt32

Convert a type to a uint.

ToUInt64

Convert a type to a ulong.

ToByte

Convert a type to a byte.

ToSByte

Convert a type to an sbyte.

ToSingle

Convert a type to a float.

ToDecimal

Convert a type to a decimal.

ToDouble

Convert a type to a double.


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 cast 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 the variable sourcedefined as a short that contains a number between 0 and 9to 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); 

Sometimes 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 exceptionsuch as converting from an sbyte to a byteit 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 in which a source-to-destination-type conversion throws an exception

Destination

Source

Exception type

bool

Char

DateTime

InvalidCastException

byte

DateTime

InvalidCastException

char

Bool

DateTime

decimal

double

float

InvalidCastException

DateTime

Bool

byte

sbyte

char

decimal

double

short

int

long

ushort

uint

ulong

float

InvalidCastException

decimal

Char

DateTime

InvalidCastException

double

Char

DateTime

InvalidCastException

short

DateTime

InvalidCastException

int

DateTime

InvalidCastException

long

DateTime

InvalidCastException

sbyte

DateTime

InvalidCastException

float

Char

DateTime

InvalidCastException

ushort

DateTime

InvalidCastException

uint

DateTime

InvalidCastException

ulong

DateTime

InvalidCastException

byte

sbyte

decimal

double

short

int

long

ushort

uint

ulong

float

OverFlowException (if source is out of the range of destination)

sbyte

Byte

decimal

double

short

int

long

ushort

uint

ulong

float

OverFlowException (if source is out of the range of destination)

short

ushort

OverFlowException (if source is out of the range of destination)

ushort

short

OverFlowException (if source is out of the range of destination)

int

uint

OverFlowException (if source is out of the range of destination)

uint

sbyte

short

int

OverFlowException (if source is out of the range of destination)

long

ulong

OverFlowException (if source is out of the range of destination)

ulong

sbyte

short

int

long

OverFlowException (if source is out of the range of destination)

Any type

string

ArgumentException (if source string is null) or FormatException (if source string represents an invalid value for the destination type)


Notice that the string type can be converted to any type, and that any type may be converted to a string typeassuming that the source string is not null and conforms to the destination type's range and format.

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.

See Also

See the "checked Keyword," "unchecked Keyword," "Checked and Unchecked," and "Convert Class" topics in the MSDN documentation.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net