To popularne pytanie. Ważne jest, aby zrozumieć, o co pyta autor pytania, i że różni się on od najprawdopodobniej najczęstszej potrzeby. Aby zniechęcić do niewłaściwego użycia kodu, gdy nie jest on potrzebny, odpowiedziałem najpierw na później.
Wspólna potrzeba
Każdy ciąg ma zestaw znaków i kodowanie. Podczas konwersji System.String
obiektu na tablicę System.Byte
nadal masz zestaw znaków i kodowanie. W przypadku większości zastosowań będziesz wiedział, jakiego zestawu znaków i kodowania potrzebujesz, a .NET ułatwia „kopiowanie z konwersją”. Po prostu wybierz odpowiednią Encoding
klasę.
// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")
Konwersja może wymagać obsługi przypadków, w których docelowy zestaw znaków lub kodowanie nie obsługuje znaku znajdującego się w źródle. Masz kilka możliwości: wyjątek, podstawienie lub pominięcie. Domyślną zasadą jest zastąpienie „?”.
// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100"));
// -> "You win ?100"
Oczywiście konwersje niekoniecznie są bezstratne!
Uwaga: w przypadku System.String
zestawu znaków źródłowych jest to Unicode.
Jedyne mylące jest to, że .NET używa nazwy zestawu znaków dla nazwy jednego konkretnego kodowania tego zestawu znaków. Encoding.Unicode
powinien zostać nazwany Encoding.UTF16
.
To tyle w przypadku większości zastosowań. Jeśli tego potrzebujesz, przestań czytać tutaj. Zobacz zabawny artykuł Joela Spolsky'ego, jeśli nie rozumiesz, czym jest kodowanie.
Szczególna potrzeba
Teraz autor pytania pyta: „Każdy ciąg jest przechowywany jako tablica bajtów, prawda? Dlaczego nie mogę po prostu mieć tych bajtów?”
On nie chce żadnego nawrócenia.
Ze specyfikacji C # :
Przetwarzanie znaków i ciągów w języku C # wykorzystuje kodowanie Unicode. Typ char reprezentuje jednostkę kodu UTF-16, a typ ciągu reprezentuje sekwencję jednostek kodu UTF-16.
Wiemy zatem, że jeśli poprosimy o konwersję zerową (tj. Z UTF-16 na UTF-16), uzyskamy pożądany wynik:
Encoding.Unicode.GetBytes(".NET String to byte array")
Ale aby uniknąć wzmianki o kodowaniu, musimy zrobić to w inny sposób. Jeśli pośredni typ danych jest dopuszczalny, istnieje do tego skrót koncepcyjny:
".NET String to byte array".ToCharArray()
To nie daje nam pożądanego typu danych, ale odpowiedź Mehrdada pokazuje, jak przekonwertować tę tablicę Char na tablicę bajtów za pomocą BlockCopy . Spowoduje to jednak skopiowanie ciągu dwukrotnie! I zbyt wyraźnie używa kodu specyficznego dla kodowania: typu danych System.Char
.
Jedynym sposobem na uzyskanie rzeczywistych bajtów, w których przechowywany jest ciąg, jest użycie wskaźnika. fixed
Zestawienie umożliwia podejmowanie adres wartości. Ze specyfikacji C #:
[Dla] wyrażenia typu ciąg, ... inicjator oblicza adres pierwszego znaku w ciągu.
Aby to zrobić, kompilator zapisuje pomijanie kodu nad innymi częściami obiektu ciągu za pomocą RuntimeHelpers.OffsetToStringData
. Tak więc, aby uzyskać nieprzetworzone bajty, po prostu stwórz wskaźnik do łańcucha i skopiuj potrzebną liczbę bajtów.
// 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;
}
Jak wskazał @CodesInChaos, wynik zależy od endianizmu maszyny. Ale autor pytania nie jest tym zainteresowany.