C'est une question populaire. Il est important de comprendre ce que l'auteur de la question pose, et qu'il est différent de ce qui est probablement le besoin le plus courant. Pour décourager l'utilisation abusive du code là où il n'est pas nécessaire, j'ai répondu le plus tard en premier.
Besoin commun
Chaque chaîne a un jeu de caractères et un encodage. Lorsque vous convertissez un System.String
objet en tableau, System.Byte
vous avez toujours un jeu de caractères et un codage. Pour la plupart des utilisations, vous savez quel jeu de caractères et quel encodage vous avez besoin et .NET facilite la «copie avec conversion». Choisissez simplement la Encoding
classe appropriée .
// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")
La conversion peut avoir besoin de gérer les cas où le jeu de caractères ou l'encodage cible ne prend pas en charge un caractère qui se trouve dans la source. Vous avez le choix: exception, substitution ou saut. La politique par défaut consiste à remplacer un «?».
// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100"));
// -> "You win ?100"
De toute évidence, les conversions ne sont pas nécessairement sans perte!
Remarque: Pour System.String
le jeu de caractères source est Unicode.
La seule chose déroutante est que .NET utilise le nom d'un jeu de caractères pour le nom d'un codage particulier de ce jeu de caractères. Encoding.Unicode
devrait être appelé Encoding.UTF16
.
C'est tout pour la plupart des utilisations. Si c'est ce dont vous avez besoin, arrêtez de lire ici. Consultez l'article amusant de Joel Spolsky si vous ne comprenez pas ce qu'est un encodage.
Besoin spécifique
Maintenant, l'auteur de la question demande: "Chaque chaîne est stockée sous forme de tableau d'octets, n'est-ce pas? Pourquoi ne puis-je pas simplement avoir ces octets?"
Il ne veut aucune conversion.
De la spécification C # :
Le traitement des caractères et des chaînes en C # utilise le codage Unicode. Le type char représente une unité de code UTF-16 et le type chaîne représente une séquence d'unités de code UTF-16.
Donc, nous savons que si nous demandons la conversion nulle (c'est-à-dire de UTF-16 en UTF-16), nous obtiendrons le résultat souhaité:
Encoding.Unicode.GetBytes(".NET String to byte array")
Mais pour éviter la mention des encodages, il faut faire autrement. Si un type de données intermédiaire est acceptable, il existe un raccourci conceptuel pour cela:
".NET String to byte array".ToCharArray()
Cela ne nous donne pas le type de données souhaité, mais la réponse de Mehrdad montre comment convertir ce tableau Char en un tableau d'octets à l'aide de BlockCopy . Cependant, cela copie la chaîne deux fois! Et, il utilise aussi explicitement du code spécifique au codage: le type de données System.Char
.
La seule façon d'accéder aux octets réels dans lesquels la chaîne est stockée est d'utiliser un pointeur. L' fixed
instruction permet de prendre l'adresse des valeurs. De la spécification C #:
[Pour] une expression de type chaîne, ... l'initialiseur calcule l'adresse du premier caractère de la chaîne.
Pour ce faire, le compilateur écrit du code sautant les autres parties de l'objet chaîne avec RuntimeHelpers.OffsetToStringData
. Donc, pour obtenir les octets bruts, créez simplement un pointeur sur la chaîne et copiez le nombre d'octets nécessaires.
// 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;
}
Comme l'a souligné @CodesInChaos, le résultat dépend de l'endianité de la machine. Mais l'auteur de la question ne s'en préoccupe pas.