Skip to content

C# - Type Conversion

Type conversion, or type casting, is the process of converting a value from one data type to another. C# is a statically-typed language, so understanding how to correctly convert between types is essential. There are two main categories of conversions: implicit and explicit.

Implicit Type Conversion (Widening Conversion)

Section titled “Implicit Type Conversion (Widening Conversion)”

Implicit conversions are performed automatically by the C# compiler when a conversion is guaranteed to be type-safe and no data will be lost. This typically happens when converting from a smaller, less precise type to a larger, more precise type (e.g., int to double).

Here, an int is implicitly and safely converted to a long and a double.

using System;
class ImplicitConversionExample {
static void Main() {
int myInt = 12345;
Console.WriteLine($"Original int: {myInt}");
// Implicitly convert int to long (safe, no data loss)
long myLong = myInt;
Console.WriteLine($"Implicitly converted to long: {myLong}");
// Implicitly convert int to double (safe, no data loss)
double myDouble = myInt;
Console.WriteLine($"Implicitly converted to double: {myDouble}");
}
}

When the above code is compiled and executed, it produces:

Original int: 12345
Implicitly converted to long: 12345
Implicitly converted to double: 12345

Explicit Type Conversion (Narrowing Conversion / Casting)

Section titled “Explicit Type Conversion (Narrowing Conversion / Casting)”

Explicit conversions require a cast operator () and are used when there is a risk of data loss or when the conversion is not obviously safe. This often occurs when converting from a larger type to a smaller type (e.g., double to int). You are telling the compiler, “I know this might lose information, but I want to do it anyway.”

This example shows converting a double to an int. The fractional part is truncated (not rounded).

using System;
class ExplicitConversionExample {
static void Main() {
double myDouble = 9876.54;
Console.WriteLine($"Original double: {myDouble}");
// Explicitly cast double to int. The fractional part is lost.
int myInt = (int)myDouble;
Console.WriteLine($"Explicitly cast to int: {myInt}");
// Another example with a larger value that doesn't fit
double largeDouble = 3000000000.0;
// This will result in an overflow if not handled carefully.
// The behavior can be unpredictable without checked context.
int overflowInt = (int)largeDouble;
Console.WriteLine($"Casting a large double to int (overflow): {overflowInt}");
}
}

When executed, this code produces:

Original double: 9876.54
Explicitly cast to int: 9876
Casting a large double to int (overflow): -1294967296

Warning: Explicit numeric casts can lead to unexpected results due to data loss or overflow. Always be certain the destination type can accommodate the source value.

C# provides built-in helper methods for more controlled and robust type conversions, especially when dealing with strings.

The System.Convert class provides a comprehensive set of methods to convert between base types. Unlike casting, it can handle a wider range of conversions (e.g., string to int) and performs rounding when converting floating-point numbers to integers.

using System;
class ConvertClassExample {
static void Main() {
double myDouble = 98.76;
string boolString = "true";
// Convert.ToInt32 rounds the double to the nearest whole number
int roundedInt = Convert.ToInt32(myDouble);
Console.WriteLine($"Convert.ToInt32({myDouble}) = {roundedInt}");
// Convert a string to a boolean
bool myBool = Convert.ToBoolean(boolString);
Console.WriteLine($"Convert.ToBoolean(\"{boolString}\") = {myBool}");
// This will throw a FormatException if the string is not a valid number
try {
int num = Convert.ToInt32("not a number");
} catch (FormatException e) {
Console.WriteLine($"Error: {e.Message}");
}
}
}

Numeric types (like int, double, etc.) have static Parse() and TryParse() methods for converting strings.

  • Parse(): Converts a string to its corresponding type. If the conversion fails (e.g., the string is not a valid number), it throws a FormatException.
  • TryParse(): (Recommended Best Practice) Attempts to convert a string and returns a bool indicating whether the conversion succeeded. It does not throw an exception on failure, making it a safer and more efficient way to handle user input or potentially invalid data.
using System;
class TryParseExample {
static void Main() {
string userInput = "123";
if (int.TryParse(userInput, out int parsedNumber)) {
// The conversion was successful
Console.WriteLine($"Successfully parsed '{userInput}' to {parsedNumber}.");
} else {
// The conversion failed
Console.WriteLine($"Failed to parse '{userInput}'.");
}
string invalidInput = "hello";
if (int.TryParse(invalidInput, out int failedParseResult)) {
Console.WriteLine($"Successfully parsed '{invalidInput}' to {failedParseResult}.");
} else {
Console.WriteLine($"Failed to parse '{invalidInput}'. It's not a valid integer.");
}
}
}

This produces the following safe output:

Successfully parsed '123' to 123.
Failed to parse 'hello'. It's not a valid integer.
MethodWhen to UseKey Behavior
Implicit ConversionWhen converting to a larger/wider type where no data can be lost (e.g., int to double).Automatic, no syntax needed.
Explicit Cast (type)When converting to a smaller/narrower type and you are aware of potential data loss.Truncates data. Can cause overflow. Fast.
Convert.To...()For general-purpose conversion between base types. Good for converting between different numeric types.Rounds numbers. Throws exception on failure.
TryParse()Best practice for converting strings to other types, especially from user input or external sources.Returns bool, does not throw exception. Safe and efficient.
Parse()When converting a string and you are certain it is valid. An exception is acceptable if it’s not.Throws exception on failure.