¿Por qué esta pregunta es tan popular en Stack Overflow?
Si alguna vez has programado en C# y te has enfrentado a la necesidad de convertir una cadena en un arreglo de bytes, seguramente te has preguntado: «¿Por qué tengo que especificar la codificación? ¡Si una cadena es solo una cadena!». Esta pregunta ha acumulado miles de visitas en Stack Overflow no por casualidad. Aborda un malentendido fundamental entre cómo vemos el texto y cómo lo ve la computadora.
En este artículo no solo daremos el código listo, sino que también entenderemos por qué Encoding.UTF8.GetBytes("hello") no es un parche, sino la única forma correcta. Aprenderás cómo obtener la representación de bytes de cadenas en C# sin riesgo de perder datos, y qué se esconde detrás de la magia de la «selección automática de codificación».
El mito de la «cadena sin codificación»
Muchos principiantes piensan que una cadena en C# es simplemente una secuencia de bytes. Esto no es así. Internamente, string en .NET se almacena como UTF-16 (caracteres de dos bytes). Cuando escribes "Привет", en memoria son 12 bytes (6 caracteres × 2 bytes). Pero si intentas enviar esta cadena a un archivo, a la red o a una base de datos, casi siempre necesitarás otro formato, generalmente UTF-8.
Intentar obtener bytes «sin codificación» es como preguntar: «¿Cómo traduzco un libro del ruso al inglés sin especificar el idioma?». Imposible. La codificación son las reglas para convertir caracteres en bytes. Sin ellas, obtendrás un desastre.
Cómo NO hacerlo (error típico)
string text = "Hello, мир!";byte[] wrongBytes = System.Text.Encoding.Default.GetBytes(text); // ¡MAL!Este código utiliza la codificación predeterminada del sistema (generalmente Windows-1251 en Windows ruso). Si ejecutas este código en otra máquina o en Linux, obtendrás bytes diferentes. Tu aplicación se volverá impredecible.
Enfoque correcto: especificación explícita de la codificación
La única forma confiable de obtener una representación de bytes consistente de cadenas es especificar explícitamente la codificación. La opción más popular y recomendada es UTF-8:
string text = "Hello, мир!";byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(text);// Resultado: [72, 101, 108, 108, 111, 44, 32, 208, 188, 208, 184, 209, 128, 33]Este código siempre dará el mismo resultado en cualquier plataforma. ¿Por qué? Porque UTF-8 es un estándar internacional que funciona igual en todas partes.
Otras opciones de codificación (cuándo se necesitan)
- ASCII — solo latín, descarta todos los caracteres >127.
- Unicode (UTF-16LE) — formato interno de C#, pero ineficiente para almacenamiento.
- Windows-1251 — legacy, solo para compatibilidad con sistemas antiguos.
Para el 99% de las tareas modernas, usa Encoding.UTF8.
¿Y si quiero «sin especificar»? ¿Hay algún truco?
Técnicamente, se puede usar BitConverter.ToString() o código unsafe con punteros, pero esto te dará los bytes crudos de UTF-16 que se almacenan en memoria. Es una mala idea por varias razones:
- El resultado depende de la plataforma (Little-Endian vs Big-Endian).
- Obtendrás bytes nulos adicionales para el latín (cada carácter ocupará 2 bytes).
- Al cambiar la versión de .NET, la representación interna podría cambiar (poco probable, pero posible).
Ejemplo de código peligroso que no debes repetir:
unsafe{ string text = "Hello"; fixed (char* ptr = text) { byte* bytePtr = (byte*)ptr; // Trabajamos con bytes crudos de UTF-16 }}Esto funciona, pero viola el principio de «no metas las manos en el interior si no entiendes las consecuencias».