Đây là một câu hỏi phổ biến. Điều quan trọng là phải hiểu những gì tác giả câu hỏi đang hỏi, và nó khác với những gì có thể là nhu cầu phổ biến nhất. Để ngăn chặn việc sử dụng sai mã không cần thiết, tôi đã trả lời sau.
Nhu cầu chung
Mỗi chuỗi có một bộ ký tự và mã hóa. Khi bạn chuyển đổi một System.String
đối tượng thành một mảng, System.Byte
bạn vẫn có một bộ ký tự và mã hóa. Đối với hầu hết các cách sử dụng, bạn sẽ biết bộ ký tự và mã hóa nào bạn cần và .NET giúp việc "sao chép với chuyển đổi" trở nên đơn giản. Chỉ cần chọn Encoding
lớp thích hợp .
// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")
Việc chuyển đổi có thể cần xử lý các trường hợp trong đó bộ ký tự đích hoặc mã hóa không hỗ trợ ký tự trong nguồn. Bạn có một số lựa chọn: ngoại lệ, thay thế hoặc bỏ qua. Chính sách mặc định là thay thế '?'.
// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100"));
// -> "You win ?100"
Rõ ràng, chuyển đổi không nhất thiết là mất mát!
Lưu ý: Đối với System.String
bộ ký tự nguồn là Unicode.
Điều khó hiểu duy nhất là .NET sử dụng tên của một bộ ký tự cho tên của một mã hóa cụ thể của bộ ký tự đó. Encoding.Unicode
nên được gọi Encoding.UTF16
.
Đó là cho hầu hết các công dụng. Nếu đó là những gì bạn cần, dừng đọc ở đây. Xem bài viết vui nhộn Joel Spolsky nếu bạn không hiểu mã hóa là gì.
Cần cụ thể
Bây giờ, tác giả câu hỏi hỏi, "Mỗi chuỗi được lưu trữ dưới dạng một mảng byte, phải không? Tại sao tôi không thể có các byte đó?"
Anh ta không muốn bất kỳ chuyển đổi.
Từ thông số kỹ thuật C # :
Xử lý ký tự và chuỗi trong C # sử dụng mã hóa Unicode. Kiểu char đại diện cho một đơn vị mã UTF-16 và loại chuỗi đại diện cho một chuỗi các đơn vị mã UTF-16.
Vì vậy, chúng tôi biết rằng nếu chúng tôi yêu cầu chuyển đổi null (nghĩa là từ UTF-16 sang UTF-16), chúng tôi sẽ nhận được kết quả mong muốn:
Encoding.Unicode.GetBytes(".NET String to byte array")
Nhưng để tránh đề cập đến mã hóa, chúng ta phải làm theo cách khác. Nếu một kiểu dữ liệu trung gian có thể chấp nhận được, có một lối tắt khái niệm cho điều này:
".NET String to byte array".ToCharArray()
Điều đó không mang lại cho chúng ta kiểu dữ liệu mong muốn nhưng câu trả lời của Mehrdad cho thấy cách chuyển đổi mảng Char này thành mảng Byte bằng cách sử dụng BlockCopy . Tuy nhiên, điều này sao chép chuỗi hai lần! Và, nó quá rõ ràng sử dụng mã dành riêng cho mã hóa: kiểu dữ liệu System.Char
.
Cách duy nhất để có được các byte thực tế mà String được lưu trữ là sử dụng một con trỏ. Các fixed
tuyên bố cho phép lấy địa chỉ của giá trị. Từ thông số kỹ thuật C #:
[Đối với] một biểu thức của chuỗi kiểu, ... trình khởi tạo sẽ tính địa chỉ của ký tự đầu tiên trong chuỗi.
Để làm như vậy, trình biên dịch ghi mã bỏ qua các phần khác của đối tượng chuỗi với RuntimeHelpers.OffsetToStringData
. Vì vậy, để có được các byte thô, chỉ cần tạo một con trỏ tới chuỗi và sao chép số byte cần thiết.
// 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;
}
Như @CodesInChaos đã chỉ ra, kết quả phụ thuộc vào độ bền của máy. Nhưng tác giả câu hỏi không quan tâm đến điều đó.