Skip to content

C# Type Conversion (and Coffee!)

Learn what it means to convert data from one type to another in C# (type conversion).

C#, like most programming languages, has several built-in data types such as integer, string, and boolean. These classifications determine the range of values a variable of that type can hold, how the data will be stored, and what can be done with the data.

Plus Operator and Numeric Types vs. String

As an example of how the type classification can impact what can be done with data, let's look at how the + ("plus") operator works differently with built-in numeric types (such as an integer) than it does with strings. If you use the + operator with two strings, the result will be the same two strings shown side-by-side. They have been "added together" in the sense that the current values are shown together.

//C# code example of + with strings

string x = "1";
string y = "2";
WriteLine($"x + y = {x + y}");

In a command-line application, the above statements result in something like:

command line output that shows the text "x + y = 12"

The plus operator concatenates the two string values and we see 12 printed to the console.

//C# code example of + with integers

int a = 1;
int b = 2;
WriteLine($"a + b = {a + b}");

In contrast, the same operator used with integers (whole numbers) will produce the sum of those two values;

command line output that shows the text "a + b = 32"

Try It!

Read through the code below. Do you know what the result of running it would be?

int a = 1;
int b = 2;

string x = "1";
string y = "2";

WriteLine($"x + b = {x + b}");

Check Your Answer

If you guessed that "x + b = 12" would be written to the screen, you are correct!

C# is Static Typed at Compile Time

C# is statically typed at compile time. Once you declare a variable, it cannot be declared again or assigned a different type without a conversion. Those familiar with looser or dynamically typed languages may be surprised at how strict the rules can be in C#.

//C# code example (produces an error)
int a = 1; 
a = "1";

In the above code example, the variable named 'a' is initially declared as an integer. The value can not be changed to a string in the next line without an error unless you explicitly change the type.

C# Type conversions are either implicit or explicit.

  • Implicit conversion: No data is lost (the conversion is type-safe), and no additional code or syntax is required.
  • Explicit conversion (cast): Data may be lost in the conversion, or there might be other issues in moving data from one type to another. A cast expression is required.

Type Conversion and Coffee (An Analogy)

Imagine that you have a full 12 oz cup of coffee that you want to pour into a different cup. The new cup happens to be 20 oz.

What will happen?

Representation of a 12 oz cup of coffee to be poured into a 20 oz cup.

It doesn't matter how much coffee is in the 12 oz cup. All of it will fit in the 20 oz cup. Transferring from the smaller cup to the larger one, you won't lose any significant amount of coffee, right?

Implicit Casting

Imagine that instead of pouring coffee between two containers, we are moving data between two different variable types.

The coffee scenario (12 oz to a 20 oz cup) is similar to implicit casting; the destination can hold all the data, and there should be no data loss. Implicit casting doesn't require special syntax or code and is called a type conversion.

//Coffee Example: integer and double
int TwelveOunceCup = 12;
double TwentyOunceCup = 0;

TwentyOunceCup = TwelveOunceCup;
  • The integer data type in C# represents a 32-bit number, and in this code example, it is being used to represent a smaller cup of coffee.
  • In contrast, the double data type in C# represents a double-precision 64-bit number.

Following the analogy, by moving the contents of a smaller cup to a larger one (from an integer to a double), there would be no data loss.

Explicit Casting

What if the coffee cup sizes were reversed, and you need to move from a 20 oz cup to a 12 oz cup?

Representation of a 20 oz cup of coffee to be poured into a 12 oz cup.

A full 20 oz cup poured into a 12oz cup would result in about 8 oz of coffee lost. If you are okay with that, or if you know that the 20 oz cup isn't full and the remaining coffee will fit in the smaller cup, then no problem.

However, to keep as much coffee as possible another solution is needed.

This second scenario (20 oz to 12 oz) is similar to explicit casting in that there is a possible loss of data.

Use explicit casting in C# to let the compiler know that although there is a possibility that data can be lost, it is okay. We are certain that the data will fit, or it won't matter if there is some data loss.

In the code example below, an int is a 12 oz cup, and a double is a 20 oz cup.

//Coffee Example 2: produces an error
int TwelveOunceCup = 0;
double TwentyOunceCup = 20;

TwelveOunceCup = TwentyOunceCup;

Error message

The error says it cannot implicitly convert from a double to an int. It recommends using a cast for an explicit conversion.

To go back to our coffee analogy, imagine the computer is worried you will be losing coffee by going from a 20 oz to a 12 oz cup. It's saying to you that there is a difference in cup sizes, and you need to be sure that you won't lose a drop of data.

In the following example, the double is cast as an integer and there is no error. The compiler is satisfied that you are taking responsibility for any loss of data.

//Coffee Example 3
int TwelveOunceCup = 0;
double TwentyOunceCup = 20;

TwelveOunceCup = (int)TwentyOunceCup;

MSDN Example (Fahrenheit to Celsius)

This operator converts from a class called Fahrenheit to a class called Celsius:

// Must be defined inside a class called Fahrenheit:
public static explicit operator Celsius(Fahrenheit fahr)
{
return new Celsius((5.0f / 9.0f) * (fahr.degrees - 32));
}

Fahrenheit fahr = new Fahrenheit(100.0f);
Console.Write("{0} Fahrenheit", fahr.Degrees);
Celsius c = (Celsius)fahr;

C# Predefined Integral Types

C# type/keyword Range Size .NET type
sbyte -128 to 127 Signed 8-bit integer System.SByte
byte 0 to 255 Unsigned 8-bit integer System.Byte
short -32,768 to 32,767 Signed 16-bit integer System.Int16
ushort 0 to 65,535 Unsigned 16-bit integer System.UInt16
int -2,147,483,648 to 2,147,483,647 Signed 32-bit integer System.Int32
uint 0 to 4,294,967,295 Unsigned 32-bit integer System.UInt32
long -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 Signed 64-bit integer System.Int64
ulong 0 to 18,446,744,073,709,551,615 Unsigned 64-bit integer System.UInt64

C# supports two floating point types: float and double, both with 32-bit single-precision.

  • The float type can represent values ranging from approximately 1.5 * 10^-45 to 3.4 * 10^38 with a precision of 7 digits.
  • The double type can represent values ranging from approximately 5.0 * 10^-324 to 1.7 × 10^308 with a precision of 15-16 digits.

 (see more about data types at microsoft.com)