Written by Mike James   
Article Index
Deep C# - Casting the Escape from Strong Typing
Upcasting
Downcasting
Generics and arrays
Custom casts

Casting is one of the most confusing aspects of any modern language and it often makes beginners think hard. But if you know why you are doing it then the how makes a lot more sense.

This is  a Chapter of our ebook on C# - a work in progress.

Deep C#

 front

 Chapter List

  1. Value And Reference
  2. Dynamic C#
  3. Passing Parameters
  4. Inheritance 
  5. Casting – the escape from strong typing
  6. Controlling Inheritance ***NEW
  7. Delegates
  8. Multicast delegates and events
  9. Anonymous Methods, Lambdas And Closures
  10. Take Exception To Everything
  11. What's The Matter With Pointers?
  12. Generics
  13. Structs
  14. The LINQ Principle
  15. XML in C#
  16. Linq and XML
  17. Regular Expressions in depth
  18. Bit Manipulation
  19. Async, Await and the UI problem
  20. The Invoke pattern
  21. The Parallel For
  22. Deep C# - Custom Attributes In C#
  23. Not so complex numbers in C#
  24. Getting Started With .NET IL
Multicast delegates and events
Tuesday, 25 May 2010
Article Index
Multicast delegates and events
Events
Generic Events

Multicast delegates are useful in their own right but they also form the basis on which the C# event system is built. We take a close look at how they work and how to use them. For example, did you know you could add and subtract delegates?

Casting – the escape from strong typing

Casting is an odd business that has found its way into many modern languages via C and C++. Both Java and C# make use of it to allow programmers to escape the confines of strong typing without being able to create anything too unsafe. The big problem is that it confuses two aspects of dealing with variables – type and representation.

Type is simply a system of classification that is used strongly typed language to determine what sort of data a variable can store or reference. Type conversion can just mean changing the classification of an object or variable or it can mean changing the actual representation of the data for example integer to floating point.

In an ideal world we wouldn’t need to convert or even mix types – an integer would always be combined with other integers and why would you ever want to convert it to a floating point number? Of course if you want to write useful programs you have to allow a certain interplay between data types and this is where casting comes in.

Casting is all about type conversion and this is how it is usually introduced but in fact there is more to it as there is are some very confused semantics behind a simple piece of syntax – just write the type name in brackets in front of the variable you want to convert – but does this mean passive type conversion or active representation conversion?

What is worse is that most books on C# don’t venture very deeply into the idea beyond presenting the basic idea that casting is just type conversion. It’s a little more tricky so let’s start simple with casting value types and then look at the more interesting reference type casting.

Type conversion

The simplest use of a cast is to convert from one numeric type to another – and this is where the active representation conversion first enters the picture. When the cast is safe from the point of view of representation then the compiler will do the job implicitly for you.

For example:

int MyInt;
long MyLong;
MyLong = MyInt;

is fine as the compiler can always store a 32-bit integer in a 64-bit integer. This is an example of a “widening” cast in the sense that the conversion is from a smaller or narrower type to a bigger or wider type.

In this case the compiler assumes that you intended to write:

MyLong = (long)MyInt;

However, if the implied cast could be unsafe then the compiler insists that you write out your intentions explicitly.

For example:

MyInt = MyLong;

will, quite rightly generate a compile time error because you can’t always convert a 64-bit integer into a 32-bit integer. This is an example of a “narrowing” cast in the sense that the conversion is from a bigger or wider type to a smaller or narrower type.

The fact that you can’t always do it doesn’t mean that it is always wrong. If you really mean it then you can write:

MyInt = (int)MyLong;

and the compiler will perform the type conversion by generating the necessary IL to convert a 32-bit integer into a 64-bit integer. Notice that there is no natural way to do this conversion and in practice C# simply moves the low 32 bits of the long value into the int.

Notice that casting only works in this way for numeric data. A beginner might suspect that if:

MyInt = (int)MyLong;

works then so should:

MyString=(string)MyInt;

but of course it doesn’t. Why it doesn’t is something we could argue about for a long time. If you are going to use casting to perform a change of representation for numeric values why not for strings and other data based objects? Instead for most active type conversions you have to use a method:

string MyString=MyInt.ToString();

There are, of course a number of versions of the ToString() method that allow you to control the format of the conversion and this makes it more flexible than the cast syntax.

Convert not cast

So the next question is – are there other conversion methods?

The answer is yes but you have to use the Convert class which, being part of the Framework, is a language neutral way of doing CLS type conversions.

So while you can’t write:

MyInt = MyLong.ToInt32();

You can write:

MyInt = Convert.ToInt32(MyLong);

Unlike the simple cast the method throws an exception if the long is too big to fit into the int.

If you want to convert a single or a double to an int then things are even more confusing as the two ways give different answers:

double MyDouble = 2.6;
MyInt = (int)MyDouble;
MyInt = Convert.ToInt32(MyDouble);

The cast truncates to give 2 but the ToInt32 rounds to give 3.

Of course if you want to take control of type conversion you can always use the Math class as in:

Math.Round(MyDouble);
Math.Truncate(MyDouble);

and there are overloaded methods that will give you control of how the rounding is to be performed. Notice however that neither method actually performs a type conversion so you will still need a cast as in:

MyInt = (int) Math.Round(MyDouble);
MyInt = (int) Math.Truncate(MyDouble);
Banner