A Quickie on Converting Between Types

You are not authorized to view comments.
johnmora's picture

This section on converting between types is specific to C#. VB .NET handles type conversion very differently and should be taken into consideration if VB .NET is your primary programming language. I’ll be briefly looking into converting between types, Boxing and what it is and implement a conversion operator.

C# does not allow implicit conversion which lose precision (Unlike VB .NET which does, “Option Strict On” in the source file turns this off). Widening Conversion is an implicit conversion when the destination type can accommodate all possible values from the source type. As an example:

   1: int i = 1;
   2: double d = 1.0001
   3: d = i;
   4: //The above conversion IS allowed.

Explicit conversion is required when the range or precision of the source type exceeds that of the destination type. This type of conversion is called Narrowing Conversion. The following list shows ways to perform explicit conversions:

System Type Visual Basic C# Converts
System.Convert     Between types that implement the System.IConvertible interface
  CType (type) cast operator Between types that define conversion operators.
type.ToString, type.Parse     Between string and to a base type; returns false if the conversion is NOT possible.
type.TryParse, type.TryParseExact     From string to a base type; returns false if the conversion is NOT possible.
  CBool, CInt, CStr, etc.   Between base types; compiled inline for better performance (VB Only)
  DirectCast, TryCast   Between types. DirectCast throws an exception if the types are not related through inheritance or if they don’t share a common interface; TryCast returns Nothing in those situations. (VB Only)

Narrowing conversions may return an incorrect result if the source value exceeds the destination type’s range. If you do not define a conversion between types a compile time error will occur.

Boxing and Unboxing

Boxing is the conversion of a value type to a reference type and unboxing does the opposite. The following example will demonstrate boxing by converting an int to an object:

   1: //Boxing example:
   2: int i = 369;
   3: object o = (object)i;
   4:  
   5: //Unboxing example:
   6: object o = 369;
   7: int i = (int)o;

You should avoid unnecessary boxing and unboxing as they incur a large amount of overhead, so avoid them when programming intensely repetitive tasks. When you call virtual methods which a structure of any value type inherits from System.Object (like ToString()), Boxing will occur also. To avoid unnecessary boxing:

  • Implement type specific conversions, overloads, when a procedure must be able to accept various value types. Several overloaded procedures are better than one procedure which accepts the Object argument.
  • Use generics, when possible, instead of arguments of the Object type.
  • Override the ToString, Equals and GetHash virtual members when defining structures.

 

Implementing Conversion in Custom Types

Conversions can be defined for your own types in several ways dependant on the type of conversion you want to perform.

  • Define conversion operators to simplify converting between numeric types.
  • Override ToString and Parse to provide conversion to strings and from strings.
  • Implement System.IConvertible which enable conversion through System.Convert (for culture specific conversions).
  • Implement a TypeConverter class for design time conversion use in Visual Studio.

Defining a conversion operator allows assigning from a value type directly to your custom type. When coding, use the Widening/implicit keyword for conversions that do not lose precision and the Narrowing explicit keyword for conversions which could lose precision. Example:

   1: struct TypeA{
   2:     public int value;
   3:  
   4:     //Allows implicit conversion from and integer
   5:     public static implicit operator TypeA(int arg){
   6:         TypeA res = new TypeA();
   7:         res.Value = arg;
   8:         return res;
   9:     }
  10:  
  11:     //Allows explicit conversion to an integer
  12:     public static explicit operator int(TypeA arg){
  13:         return arg.Value;
  14:     }
  15:  
  16:     //Provides string conversion, avoiding boxing
  17:     public override string ToString(){
  18:         return this.Value.ToString();
  19:     }
  20: }

Now you can assign integers to a variable of this type directly:

   1: TypeA a;
   2: int i;
   3: //Widening conversion is OK, implicit
   4: a = 42 //Rather than a.Value = 42
   5: //Narrowing conversion must be explicit in C#
   6: i = (int)a; //rather than i = a.Value
   7: Console.WriteLine("a = {0}, i = {1}", a.ToString(), i.ToString());

To implement the System.IConvertible interface, add the IConvertible interface to the type definition (“struct TypeA : IConvertible”) Use Visual Studio to implement the interface automatically. Member declarations for 17 methods, including GetTypeCode, ChangeType and ToType methods for each base type will be automatically generated. Every method need not be implemented some, such as ToDateTime probably would be invalid. For an invalid method simply throw an exception. Any code you do not implement, Visual Studio will automatically add code to throw an exception.

After IConvertible is implemented, the custom type can be converted using the standard System.Convert class. Example:

   1: TypeA a;
   2: bool b;
   3: a = 42;
   4: //Convert using ToBoolean
   5: b = Convert.ToBoolean(a);
   6: Console.WriteLine("a = {0}, b = {1}", a.ToString(), b.ToString();

If a conversion is not implemented, throw and InvalidCastException.

Powered by Drupal - Design by artinet