นี่เป็นคำถามยอดนิยม เป็นสิ่งสำคัญที่จะต้องเข้าใจในสิ่งที่ผู้เขียนคำถามถามและมันแตกต่างจากสิ่งที่น่าจะเป็นที่ต้องการมากที่สุด เพื่อกีดกันการใช้รหัสที่ไม่จำเป็นในทางที่ผิดฉันได้รับคำตอบในภายหลังก่อน
ความต้องการทั่วไป
สตริงทุกตัวมีชุดอักขระและการเข้ารหัส เมื่อคุณแปลง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
สำหรับประเพณีส่วนใหญ่ ถ้านั่นคือสิ่งที่คุณต้องการหยุดอ่านที่นี่ ดูบทความ Joel Spolsky ที่สนุกถ้าคุณไม่เข้าใจว่าการเข้ารหัสคืออะไร
ความต้องการเฉพาะ
ตอนนี้ผู้เขียนคำถามถามว่า "ทุกสตริงถูกเก็บไว้เป็นอาร์เรย์ไบต์ใช่มั้ยทำไมฉันถึงไม่มีไบต์เหล่านั้นไม่ได้"
เขาไม่ต้องการการแปลงใด ๆ
จากข้อกำหนดC # :
การประมวลผลอักขระและสตริงใน C # ใช้การเข้ารหัส Unicode ชนิดถ่านแสดงถึงหน่วยรหัส UTF-16 และชนิดสตริงแสดงถึงลำดับของหน่วยรหัส UTF-16
ดังนั้นเรารู้ว่าถ้าเราขอการแปลงค่าว่าง (เช่นจาก UTF-16 ถึง UTF-16) เราจะได้ผลลัพธ์ที่ต้องการ:
Encoding.Unicode.GetBytes(".NET String to byte array")
แต่เพื่อหลีกเลี่ยงการกล่าวถึงการเข้ารหัสเราต้องทำอีกวิธีหนึ่ง หากยอมรับชนิดข้อมูลระดับกลางจะมีทางลัดทางความคิดสำหรับสิ่งนี้:
".NET String to byte array".ToCharArray()
ที่ไม่ได้รับเราประเภทข้อมูลที่ต้องการ แต่Mehrdad ของคำตอบที่แสดงให้เห็นถึงวิธีการแปลงนี้แถวถ่านเป็นแถวไบต์ใช้BlockCopy อย่างไรก็ตามสิ่งนี้จะคัดลอกสตริงสองครั้ง! และมันชัดเจนเกินไปจะใช้รหัสการเข้ารหัสเฉพาะ: System.Char
ประเภทข้อมูล
วิธีเดียวที่จะไปถึงจำนวนไบต์จริงที่เก็บสตริงไว้คือใช้ตัวชี้ fixed
คำสั่งช่วยให้การอยู่ค่า จากข้อกำหนด C #:
[สำหรับ] การแสดงออกของสตริงประเภท ... initializer คำนวณที่อยู่ของตัวอักษรตัวแรกในสตริง
ต้องการทำเช่นนั้นเรียบเรียงเขียนรหัสเฮี๊ยบกว่าส่วนอื่น ๆ 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 ชี้ให้เห็นผลลัพธ์ขึ้นอยู่กับ endianness ของเครื่อง แต่ผู้เขียนคำถามไม่ได้เกี่ยวข้องกับเรื่องนั้น