Esta es una pregunta popular. Es importante comprender lo que hace el autor de la pregunta, y que es diferente de lo que probablemente sea la necesidad más común. Para desalentar el mal uso del código donde no es necesario, he respondido el primero primero.
Necesidad Común
Cada cadena tiene un conjunto de caracteres y codificación. Cuando convierte un System.String
objeto en una matriz System.Byte
, todavía tiene un conjunto de caracteres y una codificación. Para la mayoría de los usos, sabría qué conjunto de caracteres y codificación necesita y .NET simplifica la tarea de "copiar con conversión". Simplemente elija la Encoding
clase apropiada .
// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")
La conversión puede necesitar manejar casos en los que el conjunto de caracteres o la codificación de destino no admite un carácter que está en la fuente. Tiene algunas opciones: excepción, sustitución u omisión. La política predeterminada es sustituir un '?'.
// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100"));
// -> "You win ?100"
¡Claramente, las conversiones no son necesariamente sin pérdidas!
Nota: para System.String
el juego de caracteres de origen es Unicode.
Lo único confuso es que .NET usa el nombre de un conjunto de caracteres para el nombre de una codificación particular de ese conjunto de caracteres. Encoding.Unicode
debe ser llamado Encoding.UTF16
.
Eso es todo para la mayoría de los usos. Si eso es lo que necesitas, deja de leer aquí. Vea el divertido artículo de Joel Spolsky si no entiende lo que es una codificación.
Necesidad Específica
Ahora, el autor de la pregunta se pregunta: "Cada cadena se almacena como una matriz de bytes, ¿verdad? ¿Por qué no puedo simplemente tener esos bytes?"
No quiere ninguna conversión.
De la especificación C # :
El procesamiento de caracteres y cadenas en C # utiliza la codificación Unicode. El tipo char representa una unidad de código UTF-16, y el tipo de cadena representa una secuencia de unidades de código UTF-16.
Entonces, sabemos que si solicitamos la conversión nula (es decir, de UTF-16 a UTF-16), obtendremos el resultado deseado:
Encoding.Unicode.GetBytes(".NET String to byte array")
Pero para evitar la mención de codificaciones, debemos hacerlo de otra manera. Si un tipo de datos intermedio es aceptable, hay un atajo conceptual para esto:
".NET String to byte array".ToCharArray()
Eso no nos da el tipo de datos deseado, pero la respuesta de Mehrdad muestra cómo convertir esta matriz Char en una matriz Byte usando BlockCopy . Sin embargo, esto copia la cadena dos veces. Y también utiliza explícitamente el código específico de codificación: el tipo de datos System.Char
.
La única forma de llegar a los bytes reales en los que se almacena la Cadena es usar un puntero. El fixed
enunciado permite tomar la dirección de los valores. De la especificación C #:
[Para] una expresión de tipo cadena, ... el inicializador calcula la dirección del primer carácter en la cadena.
Para hacerlo, el compilador escribe el salto de código sobre las otras partes del objeto de cadena con RuntimeHelpers.OffsetToStringData
. Entonces, para obtener los bytes sin procesar, simplemente cree un puntero a la cadena y copie el número de bytes necesarios.
// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
if (s == null) return null;
var codeunitCount = s.Length;
/* We know that String is a sequence of UTF-16 codeunits
and such codeunits are 2 bytes */
var byteCount = codeunitCount * 2;
var bytes = new byte[byteCount];
fixed(void* pRaw = s)
{
Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
}
return bytes;
}
Como señaló @CodesInChaos, el resultado depende de la resistencia de la máquina. Pero el autor de la pregunta no está preocupado por eso.