C# Basics

C# Type Conversion

Conversion of one type to another is called type conversion. There are two conversion mechanisms supported by C#:


C# Implicit Type Conversion (Hidden)

If one type is converted into another type automatically by the CLR, it’s called implicit type conversion. No special casting syntax is required, and no data is lost during implicit conversion. Despite the fact that loss of precision may occur during the conversion process, which is allowed and never results in a run-time exception by the compiler, a widening primitive conversion always succeeds, where conversion is done from a smaller to a bigger data type without any risk of data being lost at all—for instance, casting an int to a double.

C# performs implicit data type conversion when types are compatible, and the compiler knows the conversion is safe. For example, the following code declares an int variable and set its value equal to 100. Because an int can always fit in a double, C# knows this is safe and doesn’t complain.

int i = 786;
double d = i; // Implicit casting from int to double

int i = 57;
// automatic type conversion
long l = i;
float f = l;

char i = '0';
int d = i;

Run Demo

The following table shows some possible implicit numeric conversions supported in C#:

From To
byte short, ushort, int, uint, long, ulong, float, double, or decimal
short int, long, float, double, or decimal
int long, float, double, or decimal
long float, double, or decimal
char ushort, int, uint, long, ulong, float, double, or decimal
float double
bool No implicit conversion
double No implicit conversion
decimal No implicit conversion

C# Explicit Type Conversion (Cast)

Explicit conversion is required when the data cannot convert from one simple-type to another automatically by the compiler or when conversion may change the value by producing an incorrect result due to the possible loss of data (narrowing conversions). To prevent a compilation error in cases where information may be lost due to an implicit conversion between types, the compiler requires you to use a cast operator to perform the type conversion. When using explicit conversion, you deliberately force the compiler to convert the value even though there is a loss of information. Keep in mind that all casts are potentially unsafe.

The following table shows some of the explicit numeric conversions for which there is no implicit conversion:

From To
byte Sbyte or char
short sbyte, byte, ushort, uint, ulong, or char
int sbyte, byte, short, ushort, uint, ulong, or char
long sbyte, byte, short, ushort, int, uint, ulong, or char
char sbyte, byte, or short
float sbyte, byte, short, ushort, int, uint, long, ulong, char, or decimal
double sbyte, byte, short, ushort, int, uint, long, ulong, char, float, or decimal
decimal sbyte, byte, short, ushort, int, uint, long, ulong, char, float, or double

Let’s look at different ways of explicit type conversion in C#.

Casting

The parentheses (( )) operator is used to explicitly cast one type to another by forcing the compiler to make the conversion. Casting works only between compatible data types, where CLR knows how to convert from one type to the other.

To perform a cast, put the target data type inside parentheses in front of the value or variable to be converted. If the cast is successful, it returns a value in that type; otherwise, it throws an exception. Take a look at the following examples.

Some of the conversions that cannot be made implicitly:

long l = 2222;

// use ( ) operator to convert a type explicitly
int i = (int)l; // Explicit casting from long to int

Now, try this one. When you cast from a double to an int, the cast simply truncates the fractional part of the double value with no rounding—thus, part of the value is lost.

double d = 786.78;

int i = d; // Incompatible Data Type
int i = (int)d; // Explicit casting from double to int

When we cast 786.78 into an integer, the resulting value is 786. The decimal portion is discarded after the conversion.

All non-integers are treated as double by default. If you want to assign a number such as 786.78 to a float or decimal, then you need to add the f or m suffix, respectively. Another way is to use a cast, as shown below:

double d = 786.78;
// Or
var d = 786.78;

float f = (float)d;
decimal dec = (decimal)d;

The values of f and dec will both be 786.78.

If you try to run the code below, an exception of type InvalidCastException is thrown with the message ‘Unable to cast object of type ‘System.String’ to type ‘System.Int32’

object val = "12";
int i = (int)val;

Run Demo

Overflow Exception Control (checked, unchecked)

C# provides a checked keyword that you can use to explicitly enable arithmetic overflow at runtime. By default, if an integer operation exceeds the maximum or minimum value that the destination type can handle, the operation keeps running without any complaint. Placing code in a checked block prevents the overflow, and instead, forces the runtime to throw an OverflowException with the message ‘Arithmetic operation resulted in an overflow.’

To throw casting errors, surround the cast into a pair of round brackets () and add the word checked in front as in the following code:

long l = long.MaxValue;
int i = checked((int)l); // OverflowException

Now, when the code executes at runtime, the program will fail because the value is too big to fit in an int.

Run Demo

If you have several statements that you want to check, you can make a checked block like below:

long a = 9999999999;
long b = long.MaxValue;

checked
{
  int a1 = (int)a;
  int b1 = (int)b;
}

Run Demo

If you want to prevent overflow checking, you can use the code as unchecked:

long l = long.MaxValue;
int i = unchecked((int)l); // OverflowException suppressed

Run Demo

Note: unchecked is the default behavior.


Converting

You can use the System.Convert class to perform conversions between base types where implicit or explicit casting isn’t possible. This class contains a complete set of static methods for both up level or down level casting and throws an InvalidCastException for failed conversions while performing a cast from one type to another.

Note: Conversion to and from all the C# number types as well as Booleans, strings, and date and time values.

The string supplied must be a valid representation of a number, and that number must be one that won’t cause an overflow. The following code uses the Convert class ToInt32 method to change the string into an int:

string val = "786";

// Conversion from string to int
int result = Convert.ToInt32(val); // Return 786

In the following example, the second statement uses the ToBoolean method to convert int to a bool value.

int val = 0;
Convert.ToBoolean(val) ; // Print False

The ToString method lets you convert the value of any variable into a textual representation.

int val = 786;
string newVal = val.ToString();

Run Demo

Note: Convert.ToInt32 internally uses the int.Parse method. The only difference is Convert.ToInt32(null) returns 0, but int.Parse(null) throws an exception of type ArgumentNullException.

Different Type of Exceptions If a Value Cannot Be Converted

FormatException: ‘Input string was not in a correct format.’

string val = "786.78";
Convert.ToInt32(val);
string val = null;
Convert.ToInt32(val); // Print 0

OverflowException: ‘Value was either too large or too small for an Int32.’

string val = "786786786786";
Convert.ToInt32(val);

InvalidCastException: ‘Invalid cast from ‘Double’ to ‘Char’

double val = 786.78;
Convert.ToChar(val);

Run Demo


Type Conversion Methods

The following table lists some of the built-in methods from the Convert class that you can use.

Methods Converts To
ToSingle A small floating point number.
ToChar Single Unicode character, where possible.
ToDateTime An integer or string type to date-time structures.
ToBoolean Boolean value, where possible.
ToByte A byte.
ToSbyte A signed byte.
ToDecimal A floating point or integer to a decimal.
ToDouble A double.
ToInt16 A 16-bit integer.
ToInt32 A 32-bit integer.
ToInt64 A 64-bit integer.
ToSingle A small floating point number.
ToType A specified type.
ToUInt16 An unsigned int.
ToUInt32 An unsigned long.
ToUInt64 An unsigned big integer.

Parsing

Parsing is used to convert the string type into a primitive value type by using built-in parsers, which are included in all the data structures of the .NET framework. You can use the Parse or TryParse methods to convert a string representation of a number to an integer, such as the System.Int32 type. If you pass an invalid string, Parse throws an exception of the type FormatException with the message “Input string was not in a correct format.” If the number is too large, an OverflowException is thrown with the message “Value was either too large or too small for an Int32.” Also, it can throw an ArgumentNullException with the message “Value cannot be null” if you pass it a null value. Conversely, TryParse will not throw any exception but instead return a Boolean value, false.

To avoid errors, you can use the TryParse method which takes two parameters: the first is the string to be parsed, and the second is an int variable with the out keyword to be filled with the value returned if the conversion succeeds.

Syntax

TryParse(string, out result)

Example

string val = "786";
int parsedValue;

bool result = Int32.TryParse(val, out parsedValue); // Return True

// With Code block

if (int.TryParse(val, out parsedValue)) {…} else {…}

Run Demo

The Parse method takes a string as a parameter and returns an int if the string contains an integer value.

Syntax

Parse(string)

Example

string val = "786";
Int32.Parse(val); // Return 786

Different Type of Exceptions If a Value Cannot Be Interpreted by the Parser

FormatException: ‘Input string was not in a correct format.’

string val = "786.78";
Int32.Parse(val);

string val = "Codebuns";
Int32.Parse(val);

ArgumentNullException: ‘Value cannot be null.’

string val = null;
Int32.Parse(val);

OverflowException: ‘Value was either too large or too small for an Int32.’

string val = "786786786786";
Int32.Parse(val);

Run Demo

Note: Each primitive type has a built-in parse method to convert a string into its associated primitive type.


C# Reference | Microsoft Docs