Это популярный вопрос. Важно понимать, что задает автор вопроса и что он отличается от того, что, вероятно, является наиболее распространенной потребностью. Чтобы воспрепятствовать неправильному использованию кода там, где он не нужен, я сначала ответил позже.
Общая потребность
Каждая строка имеет набор символов и кодировку. Когда вы конвертируете объект System.String
в массив System.Byte
, у вас все еще есть набор символов и кодировка. В большинстве случаев вы будете знать, какой набор символов и кодировку вам нужны. NET упрощает «копирование с конвертацией». " Просто выберите соответствующий класс Encoding
.
// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")
Преобразование может потребоваться для обработки случаев, когда целевой набор символов или кодировка не поддерживает символ, который находится в источнике. У вас есть несколько вариантов: исключение, замена или пропуск. Политика по умолчанию заменяет '? ».
// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100"));
// -> "You win ?100"
Очевидно, что преобразования не обязательно без потерь!
Примечание. Для System.String
исходным набором символов является Unicode.
Единственное, что сбивает с толку, так это. NET использует имя набора символов для имени одной конкретной кодировки этого набора символов. Encoding.Unicode
следует назвать Encoding.UTF16
.
Вот и все для большинства случаев. Если это то, что вам нужно, перестаньте читать здесь. См. Забавную статью 215708687 Джоэла Спольски , если вы не понимаете, что такое кодировка.
Конкретная потребность
Теперь автор вопроса задает вопрос: «Каждая строка хранится в виде массива байтов, верно? Почему я не могу просто получить эти байты? "
Он не хочет никакого преобразования.
Из C # spec :
Обработка символов и строк в C # использует кодировку Unicode. Чарс тип представляет кодовую единицу UTF-16, а тип строки представляет последовательность кодовых единиц UTF-16.
Итак, мы знаем, что если мы попросим нулевое преобразование (т.е. е. , от UTF-16 до UTF-16), мы получим желаемый результат:
Encoding.Unicode.GetBytes(".NET String to byte array")
Но чтобы избежать упоминания о кодировках, мы должны сделать это по-другому. Если промежуточный тип данных приемлем, для этого есть концептуальное сокращение:
".NET String to byte array".ToCharArray()
Это не дает нам желаемый тип данных, но ответ Мехрдада показывает, как преобразовать этот массив Char в байтовый массив, используя BlockCopy . Тем не менее, это копирует строку дважды! И он слишком явно использует код, специфичный для кодировки: тип данных System.Char
.
Единственный способ получить фактические байты, в которых хранится строка - это использовать указатель Оператор fixed
позволяет получить адрес значений. Из спецификации C #:
[For] выражение типа string,. , , инициализатор вычисляет адрес первого символа в строке.
Для этого компилятор пишет код, пропускающий другие части строкового объекта с помощью RuntimeHelpers.OffsetToStringData
. Итак, чтобы получить необработанные байты, просто создайте указатель на строку и скопируйте необходимое количество байтов.
// 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;
}
Как указал @CodesInChaos, результат зависит от порядкового номера машины. Но автора вопроса это не касается.