Esta é uma pergunta popular. É importante entender o que o autor da pergunta está fazendo e que é diferente do que é provavelmente a necessidade mais comum. Para desencorajar o uso indevido do código onde ele não é necessário, respondi primeiro mais tarde.
Necessidade comum
Cada string possui um conjunto de caracteres e codificação. Quando você converte um System.String
objeto em uma matriz, System.Byte
você ainda tem um conjunto de caracteres e codificação. Para a maioria dos usos, você saberia qual conjunto de caracteres e codificação precisa e o .NET simplifica a "cópia com conversão". Basta escolher a Encoding
classe apropriada .
// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")
A conversão pode precisar lidar com casos em que o conjunto de caracteres de destino ou a codificação não suporta um caractere que está na origem. Você tem algumas opções: exceção, substituição ou pular. A política padrão é substituir um '?'.
// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100"));
// -> "You win ?100"
Claramente, as conversões não são necessariamente sem perdas!
Nota: Para System.String
o conjunto de caracteres de origem é Unicode.
A única coisa confusa é que o .NET usa o nome de um conjunto de caracteres para o nome de uma codificação específica desse conjunto de caracteres. Encoding.Unicode
deve ser chamado Encoding.UTF16
.
É isso para a maioria dos usos. Se é isso que você precisa, pare de ler aqui. Veja o divertido artigo de Joel Spolsky se você não entender o que é uma codificação.
Necessidade específica
Agora, o autor da pergunta pergunta: "Toda string é armazenada como uma matriz de bytes, certo? Por que não posso simplesmente ter esses bytes?"
Ele não quer nenhuma conversão.
Na especificação do C # :
O processamento de caracteres e cadeias de caracteres em C # usa codificação Unicode. O tipo de caractere representa uma unidade de código UTF-16 e o tipo de sequência representa uma sequência de unidades de código UTF-16.
Portanto, sabemos que se solicitarmos a conversão nula (ou seja, de UTF-16 para UTF-16), obteremos o resultado desejado:
Encoding.Unicode.GetBytes(".NET String to byte array")
Mas, para evitar a menção de codificações, devemos fazê-lo de outra maneira. Se um tipo de dados intermediário for aceitável, existe um atalho conceitual para isso:
".NET String to byte array".ToCharArray()
Isso não nos dá o tipo de dados desejado, mas a resposta de Mehrdad mostra como converter esse array Char em um array Byte usando o BlockCopy . No entanto, isso copia a string duas vezes! E também usa explicitamente código específico da codificação: o tipo de dados System.Char
.
A única maneira de obter os bytes reais em que a String está armazenada é usar um ponteiro. A fixed
declaração permite pegar o endereço dos valores. Na especificação do C #:
[Para] uma expressão do tipo string, ... o inicializador calcula o endereço do primeiro caractere na string.
Para fazer isso, o compilador grava o código pular as outras partes do objeto string com RuntimeHelpers.OffsetToStringData
. Portanto, para obter os bytes brutos, basta criar um ponteiro para a string e copiar o número de bytes necessários.
// 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 o @CodesInChaos apontou, o resultado depende da resistência da máquina. Mas o autor da pergunta não está preocupado com isso.