C# never converts between unrelated types on its own. A string that contains digits is still a string, and a double does not quietly become an int. You convert explicitly, and which tool you use depends on what you are converting: text to a number (parsing), one numeric type to another (casting), or an object to a more specific type (as, is).
String to int: Parse, TryParse and Convert
There are three standard ways to turn text into an int:
Output:
2500
TryParse ok: 1250
TryParse failed, d = 0
42
-17
int.TryParse returns a bool and writes the result into an out variable, which is set to 0 on failure. Because bad input is normal for anything a user types, TryParse is the default choice for input, files and query strings. The same methods exist on every numeric type: long.TryParse, double.TryParse, decimal.Parse, and so on.
What each one does with bad input
The three methods differ only in how they fail:
Output:
int.Parse(null) throws ArgumentNullException
Convert.ToInt32(null) = 0
int.Parse("abc") throws FormatException
int.Parse("12.5") throws FormatException
int.Parse("1,000") throws FormatException
int.Parse("9999999999") throws OverflowException
int.Parse("") throws FormatException
A FormatException carries the familiar message "Input string was not in a correct format" (on .NET 8 and later, "The input string '12.5' was not in a correct format", with the text quoted), and it is one of the most common C# runtime errors: "12.5" is not an int, and neither is "1,000". To accept those, parse as decimal, or tell the parser which styles are allowed:
Output:
1000
255
13
10
Culture: why "1.5" can become 15
Parsing uses the current culture by default, and cultures disagree about separators. In German and several other European cultures the decimal separator is a comma and the period groups thousands. The same string gives different numbers:
Output:
1.5
15
1.5
Code that reads data files, JSON, configuration or anything machine-generated should always pass CultureInfo.InvariantCulture, both when parsing and when formatting. Otherwise the same program works on a developer's machine and misreads every number on a server set to another language. Use the current culture only for text a person typed or will read.
Implicit and explicit numeric conversions
Widening conversions happen implicitly: int to long, int to double, float to double, int to decimal. A conversion that can lose the value's magnitude or its fractional part requires an explicit cast (type)value. One exception to keep in mind: int or long to float, and long to double, are implicit even though they can lose precision: float f = 16_777_217; compiles and stores 16777216.
Output:
9 -9
10
2
4
705032704
9.99
7 7.0 7
Three things to remember. A cast from floating point to integer truncates; it does not round. Convert.ToInt32(double) rounds, using banker's rounding (halves go to the even neighbor). And an integer cast that does not fit wraps silently unless it runs in a checked context, where it throws OverflowException (see data types).
int x = 3.7; is a compile error (CS0266: cannot implicitly convert type 'double' to 'int', an explicit conversion exists), which is the compiler asking you to choose between a cast and a rounding method.
Numbers and other types to string
Every type has ToString(), and numeric types accept a format string. String interpolation calls the same formatting:
Output:
42
000042
1234.50
1,234.50
$1,234.50
FF
1010
True
Order 000042: 1234.50
The format codes (D, F, N, C, X, P, E) and custom patterns like "0.00" are covered in string interpolation.
Characters and booleans
Output:
7
55
7
7
A
True
False
1
False
(int)'7' is 55, the character's code, not 7. That trips up anyone summing digits of a number; subtract '0' or use char.GetNumericValue. bool.Parse accepts "true" and "false" in any case, and nothing else ("yes" and "1" throw).
Reference conversions: casts, as and is
For class types, a cast checks the object's actual type at run time. Upcasting to a base class is implicit. Downcasting to a derived class needs an explicit cast, which throws InvalidCastException when the object is something else:
Output:
4242
True
Card ending 4242, 50.00
InvalidCastException
5
cannot unbox int as long
Prefer is with a variable when you need to branch on the type; it is one check, it cannot throw, and the new variable is only in scope where the test succeeded. Use a plain cast when a different type would be a bug that should fail loudly. The boxed int case catches people reading numbers from object collections or DataRow cells: unbox to the exact type first ((long)(int)boxed), or use Convert.ToInt64(boxed), which handles any numeric type.
Frequently Asked Questions
How do I convert a string to an int in C#?
Use int.TryParse(text, out int number) when the text comes from a user, a file or a network: it returns false instead of throwing when the text is not a valid number. Use int.Parse(text) when invalid text is a bug and an exception is the right response. Convert.ToInt32(text) behaves like int.Parse except that it returns 0 for null.
What is the difference between int.Parse and Convert.ToInt32?
For strings they are almost the same: both throw FormatException on text like "abc" and OverflowException on out-of-range numbers. The difference is null: int.Parse(null) throws ArgumentNullException, while Convert.ToInt32(null) returns 0. Convert.ToInt32 also accepts other types (double, bool, object), and rounds a double to the nearest even integer instead of truncating.
What does "Input string was not in a correct format" mean?
It is the message of a FormatException thrown by int.Parse, double.Parse or Convert.ToInt32 (on .NET 8 and later it reads "The input string 'abc' was not in a correct format", quoting the text) when the text is not a number in the expected format: letters, an empty string, a decimal point when parsing an int, or a thousands separator. Switch to TryParse to handle bad input without an exception, and check which culture the number was written in.
How do I cast a double to an int in C#?
Write an explicit cast: int n = (int)price;. The cast truncates toward zero, so (int)9.99 is 9 and (int)-9.99 is -9. To round instead, use (int)Math.Round(price), and note that Math.Round rounds halves to the nearest even number by default; pass MidpointRounding.AwayFromZero for schoolbook rounding.
What is the difference between as and a cast in C#?
A cast (Dog)animal throws InvalidCastException if the object is not a Dog. animal as Dog returns null instead, so it must be followed by a null check, and it only works with reference and nullable types. The modern alternative is the is pattern: if (animal is Dog dog) { ... } tests and converts in one step.