Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Conversion Between Types in C#

0.00/5 (No votes)
29 Mar 2015 1  
The article will take you through the type conversion in .NET
Introduction
As we know C# is a type-safe language that I have discussed in my previous article. Type safety can be decided by the compiler at compile time or at run time by the CLR. I will explain here both of these types of type safety with some more examples and a small exercise in the end. 

At runtime the CLR knows the type of an object. We can always discover the type of the object by calling the GetType() method. Since this method is non-virtual it is impossible for the type to spoof another type. Suppose we have an employee class as shown below.   

C#
//All types is already derived from System.Object
public class Employee
{
}
public class Manager : Employee
{
}
public class SomeOtherType
{
}
Compile time type Checking
The preceding Manager class cannot override GetType() and return CEO as the class. There are basically two types of conversions that the compiler and CLR take care of in C#. They are implicit and explicit conversion. Implicit conversion takes place without any chances of data loss and that is why they are called safe explicit conversion.
Since I have defined a class Employee that implicitly derives from System.Object it is absolutely safe to create a variable of type object and assign it a reference of type Employee as shown below. In a more generalized term we can say that we can always have a variable of base type that can contain a reference of the derived type.
                                                     
C#
static void Main(string[] args)  
{  
   Object obj = new Employee(); // This is absolutely safe and compiler allows this  
   Employee emp = (Employee)obj; //This is also safe as compiler knows at the compile time that the obj contains a reference of type Employee  
   SomeOtherType otherType = (SomeOtherType)emp; //This is a compile type error for the same reason as compiler knows that obj is not a reference of SomeOtherType type  
​} 
Run time type Checking
There can be a scenario in which the compiler doesn't know the type of the object that it is casting to at compile time. The example of that is explained here.
I have a function defined as in the following.         
C#
private static void ChangeDesignation(object o)  
{  
   Employee emp = (Employee)o; // At compile time the compiler is not sure about the type of 
object o refers to that allows the code to build, but at run time  
   //the CLR checks that o should be Employee type or type derived from it, if not it throws InvalidCastException  
​}  
At compile time the compiler knows that o is the type of object and we are trying to explicitly cast o to Employee. That is fine since Employee derives from Object. Now if I want to pass an instance of type Manager in the same function, as shown below, the execution would work fine.                                      
C#
static void Main(string[] args)  
{  
   Manager manager = new Manager();  
   ChangeDesignation(manager); // This would work fine and it will create no problem at run time and in the function we can see that the  o is casted to the most base type 
only which is also safe 
   SomeOtherType otherType = new SomeOtherType();  
   ChangeDesignation(otherType);// The part of code will throw InvalidCastException at run time after it enters into the function  
​}  
Now in the next part of the code if I create an instance of SomeOtherType and pass as argument to the ChangeDesignation function the compiler would allow the code to compile but at run time we will get anInvalidCastException stating 'Unable to cast object of type 'TypeSafety.SomeOtherType' to type 'TypeSafety.Employee'.' since CLR knows that the SomeOtherType is not derived from the Employee class. This part of code was to show the Run Time Type checking. If the CLR would have allowed the cast, there would not have been any type safety and the result would have been unpredictable, including an application crash and security breaches caused by the ability of types to easily spoof other types.An easy solution to prevent this type of run time exception would have been to declare ChangeDesignation with Employee type as parameter type instead of object type so that the compiler produces a compile-time error. An object as a parameter type has been used here in this example to show the run time type checking.

Casting with the C# is and as Operators
Apart from explicit casting that we have used in the ChangeDesignation method, is to check the valid casting using the is operator. The is operator checks whether an object is compatible with a given type and the result of the evaluation is a Boolean, whether true or false. The is operator never throws an exception. Kindly check the following code:                                                                                                                                  
Object o = new Object();  
Boolean b1 = (o is object);//true 
Boolean b2 = (o is Employee);//false  
If the object reference is null, the is operator always returns false since there is no object to check its type. The isoperator could have been typically used as in the following in the ChangeDesignation function:                                                                                                    
if(o is Employee) 
   Employee emp = (Employee)o;

The CLR's type checking improves security, but it certainly comes at a performance cost, because the CLR must determine the actual type of the object referred to by the variable (o) and then the CLR must walk the inheritance hierarchy, checking each base type against the specified type (Employee). Since we need this kind of programming paradigm quite often, C# offers the as operator that simplifies our task and improves the performance bottleneck that is shown in the following code snippet:   

C#
Employee emp = o as Employee;
       if(emp != null)
       {
          //use the emp variable
       ​}
The as operator in the preceding code checks if the o is compatible with the Employee type and if it is, as returns a non-null reference to the same object. if o is not compatible, it simply returns null without throwing any exception. If we use the preceding code without checking for null, it can be dangerous as shown below:  
Object o = new Object();  
Employee e = o as Employee; //casts o to Employee which returns null  
​e.ToString();// throws exception. 

Now I would like to discuss a very interesting exercise that we would perform here and see if the code is fine or we will get a Run Time Error (RTE) or Compile Time Error (CTE) using the two classes shown below.                                                                                                                    
C#
public class Base //base class  
{  }  
public class Derived: Base //derived class  
{  }  
static void Main(string[] args)  
{  
    Object o1 = new Object(); //Works fine  
    Object o2 = new Base(); //Works fine 
    Object o3 = new Derived(); //Works fine  
    Object o4 = o3; //Works fine 
    Base b1 = new Base(); //Works fine  
    Base b2 = new Derived(); //Works fine  
    Derived d1 = new Derived(); //Works fine 
    Base b3 = new Object(); //CTE as the b3 is a varible of Base type which derives from Object.
// We can have a instance of base type and reference of derived type  
    Derived d2 = new object(); //CTE for the same reason as above  
    Base b4 = d1; //Works fine  
    Derived d3 = b2;// CTE we cannot simply convert a base class instance to derived type. we need//to tell the compiler to explicitly convert to derviced type object. it should be Derived d3 = (D//erived)b2  
    Derived d4 = (Derived) d1; //Works fine  
    Derived d5 = (Derived) b2; //Works fine  
    Derived d6 = (Derived) b1; //CTE for the reason that at compile time the compile is fine to
// cast the variable to base type, but at runtime the CLR checks that the b1 is an instance of 
//type Base which 
//contains a reference to Base type only and not the derived type  
    Base b5 = (Base) o1; //CTE for the same reason as above  
    Base b6 = (Derived) b2; //Works Fine 
​}  

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here