So far in this series we have discussed the robust type system in C# and what kinds of primitive types can exist.

Sometimes we want to take an object and change its type; for example, take a value that was an int and change it to a double, or take a float and turn it into a long. We can do this in two ways: casting and conversion.

We can also take objects of type string and attempt to change their value into a different type through parsing.

A closeup of a marble statue's feet, showing the detail on the toes and the foot jewelry.
Although our casts will be MUCH less permanent. Photo by Matt Seymour / Unsplash

The Sample Project

exceptionnotfound/CSharpInSimpleTerms
Contribute to exceptionnotfound/CSharpInSimpleTerms development by creating an account on GitHub.
Project for this post: 3CastingAndConversion

Casting

Casting is taking an object and attempting to "force" it to change types. When a cast is attempted, if the value of the object is allowable in the new type, the object will be casted into an object of the specified type.

We cast a value by placing the targeted type in parentheses () next to the value we want to cast.

C#'s compiler allows many different kinds of casting. For example, we can cast an int to a double, a char to an int, or a float to a decimal.

int five = 5;
var doubleFive = (double)five;

char a = 'a';
var valueA = (int)a;

float myFloat = 4.56F;
decimal myMoney = (decimal)myFloat;

For each of these casts (and many others) the C# compiler will "force" the value into a new variable of the specified type. This works as long as the range of the new type includes the value. However, some casts will fail because the types are not compatible, such as:

string myString = "This is a sentence";
byte myByte = (byte)myString;
Error: cannot convert 'string' to 'byte'

There is no way to determine if the value of myString can be converted to a byte, so the C# compiler will throw an error. In fact, the normal way to convert a string to any other type is through parsing, which is discussed later in this post.

Further, casting from a more-precise type to a less-precise type will result in a loss of precision:

decimal myMoney = 5.87M;
int intMoney = (int)myMoney; //Value is now 5; the .87 was lost

Because of this, we need to be careful when converting more-precise types (e.g. the floating-point numeric types) to less-precise types (int, long, char, etc).

Conversion

A conversion is similar to a cast in that it takes a value of a particular type and changes it into a value of another type. However, conversions are more forgiving than casts, generally do not lose precision, and take computationally longer to execute.

The .NET Framework provides us with a class called Convert. This class can take values from all the primitive types and attempt to convert them to all other primitive types.

int five = 5;
decimal decFive = Convert.ToDecimal(five);

decimal myMoney = 5.67M;
int intMoney = Convert.ToInt32(myMoney); //Value is now 6; 
                                         //the decimal value was rounded

When casting a floating-point numeric type to an integral numeric type, the numbers after the decimal point are lost. When converting, the value is instead rounded to the nearest whole number using a methodology known as "banker's rounding": if the number is exactly halfway between two whole numbers the even number is returned (e.g. if the number is 4.5, return 4; if the number is 5.5, return 6); otherwise, round to the nearest whole number.

The Convert class can also handle numeric to non-numeric and vice-versa conversions, such as:

string five = "5.0";
decimal decFive = Convert.ToDecimal(five); //Value is 5.0

double myValue = 5.33;
string stringValue = Convert.ToString(myValue); //Value is "5.33"

int intTrue = 1;
bool isTrue = Convert.ToBoolean(intTrue); //Value is true because number is not 0

Generally speaking, casting is faster but more prone to errors, and conversion is slower but more likely to succeed. Which one you use is a decision you have to make.

Parse()

As mentioned earlier, the string type has a unique place among the C# primitive types. Because it is a reference type, it needs special handling when converting from it to other types. We call this parsing.

The .NET Framework provides us with Parse() and TryParse() methods on each primitive type to handle converting from a string to that type.

If we needed to parse a string to a decimal, we could use the Parse() method:

string decString = "5.632";
decimal decValue = decimal.Parse(decString); //Value is 5.632M

However, if the string cannot be parsed to an acceptable value for the target type, the Parse() method will throw an exception:

string testString = "10.22.2000";
double decValue = double.Parse(testString); //Exception thrown here!

string intTest = "This is a test string";
int intValue = int.Parse(intTest); //Exception thrown here!

TryParse()

For situations where we don't know if the string value can be parsed to the desired type, we can use the method TryParse():

string value = "5.0";
decimal result;
bool isValid = decimal.TryParse(value, out result);

If isValid is true, then the string value was successfully parsed and is now the value of the variable result.

The usage of the out keyword will be explored in Part 6 (Methods, Parameters, and Arguments) of this series.

Is Keyword

There are occasions in which we do not know the specific type of a given object. Very often this happens if the code retrieved the object from another source, such as an external database, API, or service. For this situation, C# provides us with the is keyword which tests if an object is of a particular type:

var myValue = 6.5M; //M literal means type will be decimal
if(myValue is decimal) { /*...*/ }

The is keyword returns true if the object is of the specified type, and false otherwise.

As Keyword

For reference types, C# provides us with the as keyword to convert one reference type to another.

string testString = "This is a test"; //string is a reference type
object objString = (object)testString; //Cast the string to an object

string test2 = objString as string; //Will convert to string successfully

Note that this only works on valid conversions; types which do not have a defined conversion will throw an exception:

public class ClassA { /*...*/ }
public class ClassB { /*...*/ }

var myClass = new ClassA();
var newClass = myClass as ClassB; //Exception thrown here!

However, classes which inherit from one another can be freely converted using as:

public class ClassA { /*...*/ }
public class ClassB : ClassA { /*...*/ }

var myClass = new ClassA();
var convertedClass = myClass as ClassB;

We will discuss inheritance more thoroughly in Part 9 (Inheritance and Polymorphism).

GetType() and Typeof

For any given object in C#, we can get its type as an object by calling the GetType() method:

var sentence = "This is a sentence.";
var type = sentence.GetType();

We can then check if the given type is a known type, such as a primitive, a class, or others by using the typeof keyword.

var sentence = "This is a sentence.";
var type = sentence.GetType();
if(type == typeof(string)) { /*...*/ }
else if (type == typeof(int)) { /*...*/ }

Glossary

  • Casting - "Forcing" a value from one type to another type; prone to errors.
  • Conversion - Attempting to change one object's type to another; more forgiving but computationally more expensive.
  • Parsing - Attempting to convert a string to a different primitive type.

New Keywords

  • is - Used to check if a particular value is of a given type.
  • as - Used to convert an object from one type to another.
  • typeof - Returns the type of a given object.

Summary

Casting and converting are ways in which we can change a value from one type to another; casting is faster but more prone to errors, while conversion is more computationally expensive but also more forgiving.

Parsing is a special form of conversion that deals with getting a value from an object of type string and changing that value to another type.

Using the keywords is and as, we can check for type equality between two objects and determine if one object can be changed to a different type respectively.

Finally, the special method GetType() and the typeof keyword can be used to check if objects are of a particular type.

Got questions about casting, conversion, parsing, and the like? Ask questions in the comments below! The community and I are happy to help.

In the next part of this series, we'll turn our attention to some of the most basic C# features: operators. Want to learn how to do math, assignment, equality checking, and more in C#? Stick around!

Happy Coding!


Did you enjoy this post? Then you'll love my premium newsletter The Catch Block! Issues come out every Wednesday, and they have the best links to quality stories from all around the ASP.NET and web programming worlds. Plus, original stories, tips, tutorials and sample code you won't find anywhere else. Even better, it's only $5/month, or $55/year! Check out the previous issues, and then sign up to get The Catch Block today!