Это популярный вопрос. Важно понимать, что задает автор вопроса, и что он отличается от того, что, вероятно, является наиболее распространенной потребностью. Чтобы воспрепятствовать неправильному использованию кода там, где он не нужен, я ответил первым позже.
Общая потребность
Каждая строка имеет набор символов и кодировку. Когда вы конвертируете 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
.
Вот и все для большинства случаев. Если это то, что вам нужно, перестаньте читать здесь. Посмотрите забавную статью Джоэла Спольски, если вы не понимаете, что такое кодировка.
Конкретная потребность
Теперь автор вопроса спрашивает: «Каждая строка хранится в виде массива байтов, верно? Почему я не могу просто иметь эти байты?»
Он не хочет никакого обращения.
Из спецификации C # :
Обработка символов и строк в C # использует кодировку Unicode. Тип char представляет кодовую единицу 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, результат зависит от порядкового номера машины. Но автора вопроса это не касается.