ค่ากำหนดเริ่มต้นของฉัน (มาจากพื้นหลัง C ++) สำหรับ String.Format ฉันทิ้งสิ่งนี้ในภายหลังเนื่องจากสาเหตุต่อไปนี้:
- การต่อสตริงเป็นเนื้อหาที่ "ปลอดภัยกว่า" มันเกิดขึ้นกับฉัน (และฉันเคยเห็นมันเกิดขึ้นกับนักพัฒนาอื่น ๆ หลายคน) เพื่อลบพารามิเตอร์หรือทำให้ลำดับพารามิเตอร์สับสนโดยไม่ได้ตั้งใจ คอมไพลเลอร์จะไม่ตรวจสอบพารามิเตอร์กับสตริงรูปแบบและคุณพบข้อผิดพลาดรันไทม์ (นั่นคือถ้าคุณโชคดีพอที่จะไม่มีวิธีการที่คลุมเครือเช่นการบันทึกข้อผิดพลาด) ด้วยการเชื่อมต่อกันการลบพารามิเตอร์จะมีโอกาสเกิดข้อผิดพลาดน้อยกว่า คุณสามารถโต้แย้งได้ว่าโอกาสของข้อผิดพลาดนั้นน้อยมาก แต่ก็อาจเกิดขึ้นได้
- การต่อสายอักขระช่วยให้สามารถหาค่าว่างString.Format
ไม่ได้ การเขียน " s1 + null + s2
" ไม่ได้ทำลายเพียงแค่ถือว่าค่า null เป็น String.Empty สิ่งนี้อาจขึ้นอยู่กับสถานการณ์เฉพาะของคุณ - มีบางกรณีที่คุณต้องการข้อผิดพลาดแทนที่จะเพิกเฉยต่อ FirstName ที่ว่างเปล่า อย่างไรก็ตามแม้ในสถานการณ์นี้ฉันเองก็ชอบตรวจสอบ nulls ด้วยตัวเองและโยนข้อผิดพลาดเฉพาะแทนที่จะเป็น ArgumentNullException มาตรฐานที่ฉันได้รับจาก String.Format
- การต่อสตริงทำได้ดีกว่า บางส่วนของโพสต์ด้านบนได้กล่าวถึงสิ่งนี้แล้ว (โดยไม่ได้อธิบายว่าทำไมซึ่งกำหนดให้ฉันเขียนโพสต์นี้ :)
Idea คือคอมไพเลอร์. NET ฉลาดพอที่จะแปลงโค้ดชิ้นนี้:
public static string Test(string s1, int i2, int i3, int i4,
string s5, string s6, float f7, float f8)
{
return s1 + " " + i2 + i3 + i4 + " ddd " + s5 + s6 + f7 + f8;
}
สำหรับสิ่งนี้:
public static string Test(string s1, int i2, int i3, int i4,
string s5, string s6, float f7, float f8)
{
return string.Concat(new object[] { s1, " ", i2, i3, i4,
" ddd ", s5, s6, f7, f8 });
}
สิ่งที่เกิดขึ้นภายใต้ฝากระโปรงของ String Concat นั้นง่ายต่อการคาดเดา (ใช้ตัวสะท้อนแสง) วัตถุในอาร์เรย์จะถูกแปลงเป็นสตริงผ่าน ToString () จากนั้นคำนวณความยาวทั้งหมดและจัดสรรสตริงเพียงชุดเดียว (พร้อมความยาวทั้งหมด) สุดท้ายแต่ละสตริงจะถูกคัดลอกไปยังสตริงผลลัพธ์ผ่าน wstrcpy ในโค้ดบางส่วนที่ไม่ปลอดภัย
เหตุผลString.Concat
เร็วกว่าไหม เราทุกคนสามารถดูได้ว่าString.Format
กำลังทำอะไรอยู่ - คุณจะประหลาดใจกับจำนวนรหัสที่ต้องใช้ในการประมวลผลสตริงรูปแบบ นอกจากนี้ (ฉันเห็นความคิดเห็นเกี่ยวกับการใช้หน่วยความจำ) String.Format
ใช้ StringBuilder ภายใน วิธีการมีดังนี้
StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
ดังนั้นสำหรับทุกอาร์กิวเมนต์ที่ผ่านไปจะสงวนไว้ 8 อักขระ ถ้าอาร์กิวเมนต์เป็นค่าตัวเลขเดียวก็แย่เหมือนกันเรามีพื้นที่ที่สูญเปล่า หากอาร์กิวเมนต์เป็นออบเจ็กต์ที่กำหนดเองที่ส่งคืนข้อความยาวบางส่วนToString()
อาจจำเป็นต้องมีการจัดสรรใหม่ (แน่นอนว่าเป็นกรณีที่เลวร้ายที่สุด)
เมื่อเทียบกับสิ่งนี้การเรียงต่อกันจะทำให้เสียพื้นที่ของอาร์เรย์อ็อบเจ็กต์เท่านั้น (ไม่มากเกินไปโดยคำนึงว่าเป็นอาร์เรย์ของการอ้างอิง) ไม่มีการแยกวิเคราะห์สำหรับตัวระบุรูปแบบและไม่มี StringBuilder ตัวกลาง ค่าใช้จ่ายในการชกมวย / การแกะกล่องมีอยู่ในทั้งสองวิธี
เหตุผลเดียวที่ฉันเลือกใช้ String รูปแบบคือเมื่อเกี่ยวข้องกับการแปล การใส่สตริงรูปแบบในทรัพยากรช่วยให้คุณสามารถรองรับภาษาต่างๆได้โดยไม่ต้องยุ่งกับโค้ด (ลองนึกถึงสถานการณ์ที่ค่าที่จัดรูปแบบเปลี่ยนลำดับขึ้นอยู่กับภาษากล่าวคือ "หลังจาก {0} ชั่วโมงและ {1} นาที" ในภาษาญี่ปุ่นอาจดูแตกต่างกันมาก: )
สรุปโพสต์แรก (และค่อนข้างยาว) ของฉัน:
- วิธีที่ดีที่สุด (ในแง่ของประสิทธิภาพเทียบกับความสามารถในการบำรุงรักษา / ความสามารถในการอ่าน) สำหรับฉันคือการใช้การต่อสายอักขระโดยไม่ต้อง
ToString()
เรียกใด ๆ
- ถ้าคุณหลังการแสดงให้
ToString()
โทรหาตัวเองเพื่อหลีกเลี่ยงการชกมวย (ฉันค่อนข้างเอนเอียงไปทางอ่านง่าย) - เหมือนกับตัวเลือกแรกในคำถามของคุณ
- หากคุณกำลังแสดงสตริงที่แปลเป็นภาษาท้องถิ่นให้กับผู้ใช้ (ไม่ใช่ในกรณีนี้)
String.Format()
มีขอบ