Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / C#

A Beginner's Tutorial - Type Casting and Type Conversion in C#

Rate me:
Please Sign up or sign in to vote.
4.77/5 (35 votes)
26 Aug 2012CPOL6 min read 140K   580   60   26
This small article discusses about type casting in C#.

Introduction

In this short article which discusses type casting in C#, we will look into how implicit type casting works, when we will need explicit casts and how we can enhance our user defined types to support implicit or explicit casts.

Background

Programming in any language will involve manipulation of in-memory data. Accessing this in memory data is via use of variable. We can create specific type of variable to access/manipulate some data. C# allows us to create variables of many types but, being a statically typed language, it does not allow us to assign the value of one type of variable into another type of variables.

From the compiler's perspective, assigning value of one type of variable to another is perhaps not a valid operation (except for implicit casts). This also makes sense since the representation of actual data differ from type to type. But as a developer, we know and can understand the logical relationship and conversion between data types. In a lot of cases, it is almost inevitable to avoid this value assignment from one data type to another.

For the above mentioned reasons, C# has provided the possibility of casting one data type to another. Not only that, it also provides us the flexibility to take full control over casting in our hands (user defined conversions). Along with that, it has a lot of helper classes built in the library that provides most of the frequently needed casting operations.

Using the Code

Let us look at different ways of casting/conversion possible in C#. 

Implicit Casts

Let us start by looking into the conversions that are done automatically by C#. Implicit casts are the casts that do not require the programmer to do an explicit conversion. One data type can simply be assigned to another. There are some rules that govern the implicit cast.

  1. Built-in numeric types, widening conversions
  2. Reference types, Derived class to base class

The built in numeric types can be assigned to each other if a narrow type is being assigned to wider type. This is possible because the compiler knows that the only problem in such operations is that a little more memory will be needed to hold this type and no data will be truncated or lost. So the following conversion will not need any explicit cast. 

C#
int i = 10;
long l = i;

Secondly, If we try to assign a value from derived class to a base class, it will work. That is because a derived class always is-a base class. Also, from a memory perspective, a base class variable pointing to a derived class object can safely access the base class part of the object in memory without any problem. So, the following code will work without needing any explicit casts.

C#
class Base
{

}

class Derived : Base
{

}   

class Program
{
    static void Main(string[] args)
    {
        Derived d = new Derived();
        Base b = d;      
    }
}

Other than these two possible scenarios, all the conversions will create compile time errors. Still, If we need to perform the conversions, we will have to use explicit casting/conversion.

Explicit Casts

If we find ourselves in need of conversion that is either narrowing conversion or conversion between unrelated types, then we will have to use explicit conversions. Using explicit conversions, we are actually letting the compiler know that we know there is possible information loss but still we need to make this conversion. So if we need to convert a long type to an integer type, we need to cast it explicitly.

C#
long l = 10;
int i = (int)l;

On similar lines, if we need to cast a base class to a derived class, I will have to cast it explicitly.

C#
Base b = new Base();
Derived d = (Derived)b;

Explicit casting actually tells the compiler that we know about possible information loss/mismatch but still we need to perform this cast. This is ok for inbuilt numeric types but in case of reference types, there is a possibility that the types are not at all compatible, i.e., casting from one type to another is not at all possible. For example, casting a string "abc" to Integer is not possible.

Such casting expressions will compile successfully, but they will fail at run-time. What C# compiler does is that it checks whether these two types are cast compatible or not and if not, it raises an exception InvalidCastException.

'is' and 'as' operators

So whenever we are using explicit casts, it is always a good idea to wrap the cast inside a try-catch block. C# also provides is and as operators which are helpful in performing explicit casts in an exception safe manner. 

The is operator checks whether the type being casted from is compatible to the type being casted to and returns a boolean value. So the exception safe way to perform an explicit cast using is operator would be: 

C#
static void Main(string[] args)
{   
    // CASE 1 *****
    // This will work fine as o1 is actually an int
    object o1 = 1;
    int i = (int)o1;

    // CASE 2 *****
    // This won't work because o2 is not an int, so we need 
    // to have an is operator before the actual cast
    object o2 = "1";
    int j;

    if (o2 is int)
    {
        j = (int)o2;
    }

    // CASE 3 *****
    // We can never know what is the actual type of 
    // an object at runtime, so it's always better to use 
    // is operator, rewriting the first case
    object o3 = 1;
    int k;

    if (o3 is int)
    {
        k = (int)o3;
    }
}

Case 1 in the above code snippet will throw an exception is o1 is assigned to some type that is not int, the other two cases are exception safe and will only perform the cast if the types are compatible for casting.

There is one small performance issue in using is operator. Case 3 in the above code snippet will work fine but it involves accessing the object twice. Once for checking the compatibility, i.e., the is operator and secondly to actually extract out the value, i.e., casting. Can we not have something like - "Check the compatibility and if compatible, perform the cast" in one single operation. That is where the as operator comes into the picture.

The as operator checks the compatibility and if it's OK, it will perform the cast too. If the cast is not compatible or unsuccessful, then the result will be null. So, the above cast can be rewritten using the as operator:

C#
object o3 = 1;
int? k = o3 as int?;

if (k != null)
{
    //use k for whatever we want to
    Console.WriteLine(k.Value);
}

Note: The important thing to note here is that the as operator can only be used with reference types. This is the reason we used nullable int in the above example.

So, if we need to have an exception safe casting, we can use is or as operator. We should use is operator if the target type is a value type and as operator if the target type is a reference type.

User Defined Conversions

C# also provides the flexibility for defining conversions on classes and structs so that they can be converted to and from other. The conversion operators simply contain the logic of how the conversion should happen. We can define these conversion operators to be implicit or explicit. If we define them implicit, the conversion will happen without needing as explicit cast. If we define it as explicit, the casting will be required.

Let us try to see how we can implement these conversion operations. Let us implement a small class Rational to hold rational number. We will then define two conversion operations. Int to Rational (an implicit conversion) and Rational to double (an explicit conversion).

C#
class Rational
{
    int numerator;
    int denominator;

    public Rational(int num, int den)
    {
        numerator = num;
        denominator = den;
    }

    public static implicit operator Rational(int i)
    {
        // since the rational equivalent of an int has 1 as denominator
        Rational rational = new Rational(i, 1);

        return rational;
    }

    public static explicit operator double(Rational r)
    {
        double result = ((double)r.numerator) / r.denominator;
        return result;
    }
}

And now, let us see how we can use these conversion operators to perform actual conversions:

C#
static void Main(string[] args)
{   
    // Conversion from int to rational is implicit
    Rational r1 = 23;

    // Conversion from rational to double is explicit
    Rational r2 = new Rational(3, 2);
    double d = (double)r2;
}

Before wrapping up, there is one more thing that beginners should be aware of. There are a lot of helper classes and helper functions available in C# to perform the frequently needed conversions. It is always a good idea to refer to the documentation to achieve the desired conversions before putting in the code for conversions. Following code snippet shows how we can convert string to int using Convert class.

C#
static void Main(string[] args)
{  
    string s = "123";

    try
    {
        int i = Convert.ToInt32(s);
    }
    catch (Exception ex)
    {
        // Pokemon exception handling, ideally rectification 
        // code and logging should be done here
    }    
}

Points of Interest

Conversion from one type to another is inevitable in any programming language. Knowing the basics about conversions will let us use the right approach in the right scenario. This small article discussed the same about C#. This has been written for beginners so some of the experienced programmers could find this article futile. Nevertheless, I hope this has been informative.

History

  • 27th August, 2012: First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
India India

I Started my Programming career with C++. Later got a chance to develop Windows Form applications using C#. Currently using C#, ASP.NET & ASP.NET MVC to create Information Systems, e-commerce/e-governance Portals and Data driven websites.

My interests involves Programming, Website development and Learning/Teaching subjects related to Computer Science/Information Systems. IMO, C# is the best programming language and I love working with C# and other Microsoft Technologies.

  • Microsoft Certified Technology Specialist (MCTS): Web Applications Development with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Accessing Data with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Windows Communication Foundation Development with Microsoft .NET Framework 4

If you like my articles, please visit my website for more: www.rahulrajatsingh.com[^]

  • Microsoft MVP 2015

Comments and Discussions

 
GeneralMy vote of 5 Pin
P.Salini13-Sep-12 2:32
P.Salini13-Sep-12 2:32 
AnswerRe: My vote of 5 Pin
Rahul Rajat Singh13-Sep-12 2:35
professionalRahul Rajat Singh13-Sep-12 2:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.