C# nunca convierte por sí solo entre tipos sin relación. Un string que contiene dígitos sigue siendo un string, y un double no se convierte en silencio en un int. Conviertes de forma explícita, y la herramienta depende de lo que conviertes: texto a número (parseo), un tipo numérico a otro (cast) o un objeto a un tipo más específico (as, is).
String a int: Parse, TryParse y Convert
Hay tres formas habituales de convertir texto en un int:
Salida:
2500
TryParse ok: 1250
TryParse failed, d = 0
42
-17
int.TryParse devuelve un bool y escribe el resultado en una variable out, que se pone a 0 si falla. Como la entrada incorrecta es algo normal en todo lo que escribe un usuario, TryParse es la opción por defecto para la entrada, los archivos y los parámetros de consulta. Los mismos métodos existen en todos los tipos numéricos: long.TryParse, double.TryParse, decimal.Parse, etc.
Qué hace cada uno con una entrada incorrecta
Los tres métodos solo se diferencian en cómo fallan:
Salida:
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
Una FormatException lleva el conocido mensaje "Input string was not in a correct format" (en .NET 8 y posteriores, "The input string '12.5' was not in a correct format", con el texto citado), y es uno de los errores de ejecución más comunes de C#: "12.5" no es un int, y "1,000" tampoco. Para aceptarlos, parsea como decimal o dile al parser qué estilos se permiten:
Salida:
1000
255
13
10
Cultura: por qué "1.5" puede convertirse en 15
El parseo usa por defecto la cultura actual, y las culturas no coinciden en los separadores. En alemán y en otras culturas europeas, el separador decimal es la coma y el punto agrupa los miles. El mismo string da números distintos:
Salida:
1.5
15
1.5
El código que lee archivos de datos, JSON, configuración o cualquier cosa generada por una máquina debería pasar siempre CultureInfo.InvariantCulture, tanto al parsear como al dar formato. Si no, el mismo programa funciona en la máquina de un desarrollador y lee mal todos los números en un servidor configurado en otro idioma. Usa la cultura actual solo para el texto que escribe o va a leer una persona.
Conversiones numéricas implícitas y explícitas
Las conversiones de ampliación ocurren de forma implícita: de int a long, de int a double, de float a double, de int a decimal. Una conversión que puede perder la magnitud del valor o su parte fraccionaria exige un cast explícito (type)value. Hay una excepción que conviene recordar: de int o long a float, y de long a double, son implícitas aunque puedan perder precisión: float f = 16_777_217; compila y guarda 16777216.
Salida:
9 -9
10
2
4
705032704
9.99
7 7.0 7
Tres cosas que recordar. Un cast de coma flotante a entero trunca; no redondea. Convert.ToInt32(double) redondea, con el redondeo bancario (las mitades van al vecino par). Y un cast entero que no cabe da la vuelta en silencio salvo que se ejecute en un contexto checked, donde lanza OverflowException (consulta tipos de datos).
int x = 3.7; es un error de compilación (CS0266: cannot implicitly convert type 'double' to 'int', an explicit conversion exists), que es el compilador pidiéndote que elijas entre un cast y un método de redondeo.
Números y otros tipos a string
Todo tipo tiene ToString(), y los tipos numéricos aceptan un string de formato. La interpolación de strings llama al mismo formato:
Salida:
42
000042
1234.50
1,234.50
$1,234.50
FF
1010
True
Order 000042: 1234.50
Los códigos de formato (D, F, N, C, X, P, E) y los patrones propios como "0.00" se explican en interpolación de strings.
Caracteres y booleanos
Salida:
7
55
7
7
A
True
False
1
False
(int)'7' es 55, el código del carácter, no 7. Eso despista a cualquiera que sume los dígitos de un número; resta '0' o usa char.GetNumericValue. bool.Parse acepta "true" y "false" en cualquier combinación de mayúsculas, y nada más ("yes" y "1" lanzan una excepción).
Conversiones de referencia: casts, as e is
En los tipos de clase, un cast comprueba en tiempo de ejecución el tipo real del objeto. Convertir hacia una clase base es implícito. Convertir hacia una clase derivada necesita un cast explícito, que lanza InvalidCastException cuando el objeto es otra cosa:
Salida:
4242
True
Card ending 4242, 50.00
InvalidCastException
5
cannot unbox int as long
Prefiere is con una variable cuando necesites ramificar según el tipo; es una sola comprobación, no puede lanzar excepciones y la variable nueva solo está en ámbito donde la prueba tuvo éxito. Usa un cast normal cuando un tipo distinto sería un bug que debe fallar de forma ruidosa. El caso del int con boxing pilla a quien lee números de colecciones object o de celdas de un DataRow: haz primero el unboxing al tipo exacto ((long)(int)boxed), o usa Convert.ToInt64(boxed), que maneja cualquier tipo numérico.
Preguntas frecuentes
¿Cómo convierto un string a int en C#?
Usa int.TryParse(text, out int number) cuando el texto viene de un usuario, un archivo o la red: devuelve false en lugar de lanzar una excepción cuando el texto no es un número válido. Usa int.Parse(text) cuando un texto no válido es un bug y una excepción es la respuesta adecuada. Convert.ToInt32(text) se comporta como int.Parse, salvo que devuelve 0 para null.
¿Qué diferencia hay entre int.Parse y Convert.ToInt32?
Con strings son casi iguales: los dos lanzan FormatException con un texto como "abc" y OverflowException con números fuera de rango. La diferencia es null: int.Parse(null) lanza ArgumentNullException, mientras que Convert.ToInt32(null) devuelve 0. Convert.ToInt32 también acepta otros tipos (double, bool, object), y redondea un double al entero par más cercano en lugar de truncarlo.
¿Qué significa "Input string was not in a correct format"?
Es el mensaje de una FormatException lanzada por int.Parse, double.Parse o Convert.ToInt32 (en .NET 8 y posteriores dice "The input string 'abc' was not in a correct format", citando el texto) cuando el texto no es un número en el formato esperado: letras, un string vacío, un punto decimal al parsear un int o un separador de miles. Cambia a TryParse para manejar la entrada incorrecta sin excepción, y comprueba en qué cultura se escribió el número.
¿Cómo convierto un double a int en C#?
Escribe un cast explícito: int n = (int)price;. El cast trunca hacia cero, así que (int)9.99 es 9 y (int)-9.99 es -9. Para redondear, usa (int)Math.Round(price), y ten en cuenta que Math.Round redondea por defecto las mitades al número par más cercano; pasa MidpointRounding.AwayFromZero para el redondeo escolar.
¿Qué diferencia hay entre as y un cast en C#?
Un cast (Dog)animal lanza InvalidCastException si el objeto no es un Dog. animal as Dog devuelve null en su lugar, así que debe ir seguido de una comprobación de null, y solo funciona con tipos de referencia y nullable. La alternativa moderna es el patrón is: if (animal is Dog dog) { ... } comprueba y convierte en un solo paso.