เอาต์พุตสตริง: รูปแบบหรือ concat ใน C #?


178

สมมติว่าคุณต้องการส่งออกหรือสตริง concat คุณชอบสไตล์ใดต่อไปนี้

  • var p = new { FirstName = "Bill", LastName = "Gates" };

  • Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

  • Console.WriteLine(p.FirstName + " " + p.LastName);

คุณค่อนข้างใช้รูปแบบหรือคุณเพียงแค่เชื่อมสตริง? คุณชอบอะไร หนึ่งในสิ่งเหล่านี้ทำร้ายดวงตาของคุณหรือไม่?

คุณมีเหตุผลที่จะใช้เหตุผลข้อหนึ่งหรือไม่?

ฉันจะไปอีกครั้ง

คำตอบ:


88

ลองรหัสนี้

มันเป็นรหัสของคุณที่ได้รับการแก้ไขเล็กน้อย
1. ฉันลบ Console.WriteLine เนื่องจากอาจมีขนาดของคำสั่งช้ากว่าสิ่งที่ฉันพยายามวัด
2. ฉันเริ่มนาฬิกาจับเวลาก่อนที่จะวนซ้ำและหยุดทันทีวิธีนี้ฉันจะไม่สูญเสียความแม่นยำหากฟังก์ชันใช้ตัวอย่างเช่น 26.4 เห็บเพื่อดำเนินการ
3. วิธีที่คุณแบ่งผลลัพธ์โดยการวนซ้ำนั้นผิด ดูว่าเกิดอะไรขึ้นถ้าคุณมี 1,000 มิลลิวินาทีและ 100 มิลลิวินาที ในทั้งสองสถานการณ์คุณจะได้รับ 0 ms หลังจากหารด้วย 1000000

Stopwatch s = new Stopwatch();

var p = new { FirstName = "Bill", LastName = "Gates" };

int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;

string result;
s.Start();
for (var i = 0; i < n; i++)
    result = (p.FirstName + " " + p.LastName);
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();
s.Start();
for (var i = 0; i < n; i++)
    result = string.Format("{0} {1}", p.FirstName, p.LastName);
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();


Console.Clear();
Console.WriteLine(n.ToString()+" x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Thread.Sleep(4000);

นี่คือผลลัพธ์ของฉัน:

1000000 x result = string.Format ("{0} {1}", p.FirstName, p.LastName); เอา: 618ms - 2213706 ติ๊ก
1000000 x ผลลัพธ์ = (p.FirstName + "" + p.LastName); เอา: 166ms - 595610 เห็บ


1
น่าสนใจมาก. ฉันได้รับค่าเฉลี่ย 224ms เทียบกับ 48 มิลลิวินาทีปรับปรุง x4.66 ดีกว่าของคุณ x3.72 ฉันสงสัยว่ามีเครื่องมือ post-compilation ที่สามารถเขียน IL string.Formatที่ไม่ได้ใช้คุณสมบัติการจัดรูปแบบคอมโพสิตใด ๆ (เช่นง่าย ๆ{0}) และแทนที่ด้วยการต่อสตริงที่เร็วขึ้นอย่างมาก ฉันสงสัยว่าความสำเร็จดังกล่าวสามารถทำได้โดยนักเขียน IL คนปัจจุบันเช่น PostSharp
Allon Guralnek

31
สตริงไม่สามารถเปลี่ยนแปลงได้ซึ่งหมายถึงหน่วยความจำขนาดเล็กชิ้นเดียวกันนี้ถูกใช้ซ้ำในโค้ดของคุณ การเพิ่มสองสตริงเดียวกันเข้าด้วยกันและสร้างสตริงใหม่ซ้ำแล้วซ้ำอีกจะไม่ส่งผลกระทบต่อหน่วยความจำ . Net ฉลาดพอที่จะใช้การอ้างอิงหน่วยความจำเดียวกัน ดังนั้นโค้ดของคุณจึงไม่ได้ทดสอบความแตกต่างระหว่างสองวิธีการต่อกัน ดูรหัสในคำตอบของฉันด้านล่าง
Ludington

1
สุจริตฉัน concatenate เสมอเพราะมันง่ายต่อการอ่านสำหรับฉันและว้าวเร็วขึ้น :)
puretppc

เหตุใดความเร็วจึงเป็นเหตุผลเดียวที่จะเลือกสิ่งใดสิ่งหนึ่ง?
niico

158

ฉันประหลาดใจที่ผู้คนจำนวนมากต้องการค้นหารหัสที่ดำเนินการได้เร็วที่สุดในทันที หากการทำซ้ำหนึ่งล้านยังคงใช้เวลาน้อยกว่าหนึ่งวินาทีในการดำเนินการสิ่งนี้จะเป็นไปในลักษณะใดที่ผู้ใช้ปลายทางเห็นได้หรือไม่? ไม่น่าจะเป็นไปได้มาก

การเพิ่มประสิทธิภาพก่อนกำหนด = FAIL

ฉันจะไปกับString.Formatตัวเลือกเพียงเพราะมันเหมาะสมที่สุดจากมุมมองทางสถาปัตยกรรม ฉันไม่สนใจเกี่ยวกับการแสดงจนกว่ามันจะกลายเป็นปัญหา (และถ้าเป็นเช่นนั้นฉันจะถามตัวเองว่า: ฉันต้องเชื่อมต่อชื่อหลายล้านชื่อพร้อมกันหรือไม่แน่นอนพวกเขาจะไม่พอดีกับหน้าจอ ... )

พิจารณาว่าลูกค้าของคุณต้องการเปลี่ยนในภายหลังเพื่อให้สามารถกำหนดค่าว่าจะแสดง"Firstname Lastname"หรือ"Lastname, Firstname."ด้วยตัวเลือกรูปแบบนี่เป็นเรื่องง่าย - เพียงแค่สลับสตริงรูปแบบ ด้วยการต่อคุณจะต้องใช้รหัสพิเศษ แน่ใจว่าไม่ฟังดูเป็นเรื่องใหญ่ในตัวอย่างนี้ แต่คาดการณ์


47
จุดที่ดีในแง่ของ "การเพิ่มประสิทธิภาพก่อนกำหนด == ความล้มเหลว" ใช่ แต่เมื่อคุณเริ่มจ่ายเงินเพื่อดำเนินการตามรอยเท้า (คลาวด์และโครงสร้างพื้นฐานเป็นบริการทุกคน?) และ / หรือคุณเริ่มสนับสนุนผู้ใช้ 1 ล้านคนในบางสิ่งบางอย่างแล้วการตอบสนองต่อผู้ใช้คนเดียวในคำขอไม่ใช่คำถาม ค่าใช้จ่ายในการให้บริการตามคำขอของผู้ใช้เป็นค่าใช้จ่ายสำหรับกำไรของคุณเช่นเดียวกับปัญหาในกรณีที่ / เมื่อมีการโทรเข้ามาหลายพันครั้ง ...
Aidanapword

23
นี่เป็นเพียงความผิดทั้งหมด ในสภาพแวดล้อมการพัฒนาเว็บบ่อยครั้งที่รหัสการสร้างสตริงของคุณจะลึกทั้งในรูปแบบมุมมองและตัวควบคุมของคุณและสามารถเรียกได้หลายหมื่นครั้งต่อการโหลดหน้าเว็บ การลดระยะเวลาที่ใช้ในการประเมินโค้ดการสร้างสตริง 50% อาจเป็นชัยชนะครั้งใหญ่
Benjamin Sussman

2
คำถามเช่นนี้ไม่ได้นำไปใช้กับอินสแตนซ์เดียวของ OP คำตอบคือสิ่งที่ผู้คนสามารถจำได้ว่าเป็น "ฉันควรประกอบสายไหน" ขณะที่พวกเขาเขียนทั้งหมดของรหัสของพวกเขา
Phil Miller

6
@Benjamin: ... ในกรณีนี้คุณจะต้องโพรไฟล์และพบว่าเป็นคอขวดของคุณ ฉันจะเดิมพันเงินที่คุณเพิ่งจะดึงมันมาจากไหนไม่รู้ ในอดีตที่ผ่านมามีการเขียนและทำ webapps เป็นจำนวนมากฉันมักจะพบว่าคอขวดในเวลาตอบสนอง(บนเซิร์ฟเวอร์)เป็นคำถามฐานข้อมูล
BlueRaja - Danny Pflughoeft

2
นี่ไม่ใช่การเพิ่มประสิทธิภาพก่อนเวลาอันควรอย่างแน่นอน ค่อนข้างเข้าใจผิด ประสิทธิภาพของสตริงสามารถหยุด UIs ได้อย่างสมบูรณ์โดยเฉพาะใน. NET หากคุณทำการฟอร์แมตและการสร้างสตริงจำนวนมาก ubiquity.acm.org/article.cfm?id=1513451
user99999991

54

โอ้ที่รัก - หลังจากอ่านหนึ่งในคำตอบอื่น ๆ ที่ฉันพยายามกลับคำสั่งของการดำเนินการ - ดังนั้นการดำเนินการเรียงต่อกันก่อนแล้วจึง String.Format ...

Bill Gates
Console.WriteLine(p.FirstName + " " + p.LastName); took: 8ms - 30488 ticks
Bill Gates
Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took: 0ms - 182 ticks

คำสั่งของการดำเนินการสร้างความแตกต่างอย่างมากหรือเป็นการดำเนินการครั้งแรกค่อนข้างช้ากว่ามาก

นี่คือผลลัพธ์ของการรันที่การดำเนินการเสร็จสิ้นมากกว่าหนึ่งครั้ง ฉันได้ลองเปลี่ยนคำสั่ง แต่สิ่งต่าง ๆ ปฏิบัติตามกฎเดียวกันเมื่อผลลัพธ์แรกถูกละเว้น:

Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 5ms - 20335 ticks
Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 0ms - 156 ticks
Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 0ms - 122 ticks
Bill Gates
Console.WriteLine("{0} {1}", FirstName, LastName); took: 0ms - 181 ticks
Bill Gates
Console.WriteLine("{0} {1}", FirstName, LastName); took: 0ms - 122 ticks
Bill Gates
String.Concat(FirstName, " ", LastName); took: 0ms - 142 ticks
Bill Gates
String.Concat(FirstName, " ", LastName); took: 0ms - 117 ticks

ในขณะที่คุณสามารถเห็นการทำงานที่ตามมาของวิธีการเดียวกัน (ฉัน refactored รหัสเป็น 3 วิธี) จะเพิ่มขึ้นเร็วขึ้น ความเร็วที่เร็วที่สุดนั้นจะเป็นวิธี Console.WriteLine (String.Concat (... )) ตามด้วยการต่อข้อมูลแบบปกติและการดำเนินการที่จัดรูปแบบแล้ว

การหน่วงเวลาเริ่มต้นในการเริ่มต้นน่าจะเป็นการเริ่มต้นของสตรีมคอนโซลเช่นการวาง Console.Writeline ("เริ่มต้น!") ก่อนที่การดำเนินการครั้งแรกจะนำกลับเข้าบรรทัดทั้งหมด


2
จากนั้นลบ Console.WriteLine ออกจากการทดสอบของคุณโดยสมบูรณ์ มันบิดเบือนผลลัพธ์!
CShark

ฉันมักจะเริ่มต้นด้วยใบปลิวหรือ "ควบคุม" สถานการณ์เมื่อใช้การทดสอบประสิทธิภาพด้วยเหตุผลนี้แน่นอน
drzaus

36

สตริงไม่สามารถเปลี่ยนแปลงได้ซึ่งหมายถึงหน่วยความจำขนาดเล็กชิ้นเดียวกันนี้ถูกใช้ซ้ำในโค้ดของคุณ การเพิ่มสองสตริงเดียวกันเข้าด้วยกันและสร้างสตริงใหม่ซ้ำแล้วซ้ำอีกจะไม่ส่งผลกระทบต่อหน่วยความจำ . Net ฉลาดพอที่จะใช้การอ้างอิงหน่วยความจำเดียวกัน ดังนั้นโค้ดของคุณจึงไม่ได้ทดสอบความแตกต่างระหว่างสองวิธีการต่อกัน

ลองใช้ขนาดนี้ดู:

Stopwatch s = new Stopwatch();

int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0, sbElapsedMilliseconds = 0, sbElapsedTicks = 0;

Random random = new Random(DateTime.Now.Millisecond);

string result;
s.Start();
for (var i = 0; i < n; i++)
    result = (random.Next().ToString() + " " + random.Next().ToString());
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();

s.Start();
for (var i = 0; i < n; i++)
    result = string.Format("{0} {1}", random.Next().ToString(), random.Next().ToString());
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();

StringBuilder sb = new StringBuilder();
s.Start();
for(var i = 0; i < n; i++){
    sb.Clear();
    sb.Append(random.Next().ToString());
    sb.Append(" ");
    sb.Append(random.Next().ToString());
    result = sb.ToString();
}
s.Stop();
sbElapsedMilliseconds = s.ElapsedMilliseconds;
sbElapsedTicks = s.ElapsedTicks;
s.Reset();

Console.WriteLine(n.ToString() + " x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x sb.Clear();sb.Append(random.Next().ToString()); sb.Append(\" \"); sb.Append(random.Next().ToString()); result = sb.ToString(); took: " + (sbElapsedMilliseconds) + "ms - " + (sbElapsedTicks) + " ticks");
Console.WriteLine("****************");
Console.WriteLine("Press Enter to Quit");
Console.ReadLine();

ตัวอย่างผลลัพธ์:

1000000 x result = string.Format("{0} {1}", p.FirstName, p.LastName); took: 513ms - 1499816 ticks
1000000 x result = (p.FirstName + " " + p.LastName); took: 393ms - 1150148 ticks
1000000 x sb.Clear();sb.Append(random.Next().ToString()); sb.Append(" "); sb.Append(random.Next().ToString()); result = sb.ToString(); took: 405ms - 1185816 ticks

1
เพิ่ม StringBuilder และส่งออกตัวอย่างไปยังคำตอบ
mikeschuld

ฉันเห็นว่าการใช้string.Formatนั้นคุ้มค่ากับประสิทธิภาพเพียงเล็กน้อยที่นี่ สถาปัตยกรรมจะดีกว่าเนื่องจากคุณสามารถเปลี่ยนรูปแบบได้ง่ายขึ้น แต่ผู้สร้างสตริงฉันไม่เห็นจุดของ ทุกเธรดอื่นที่นี่บอกว่าคุณควรใช้ Stringbuilder แทนการเชื่อมโยงสตริง ข้อดีคืออะไร เห็นได้ชัดว่าไม่เร็วตามมาตรฐานนี้พิสูจน์
roryok

22

สงสารนักแปลที่น่าสงสาร

ถ้าคุณรู้แอปพลิเคชันของคุณจะเป็นภาษาอังกฤษให้ทำตามนั้นบันทึกนาฬิกาติ๊ก อย่างไรก็ตามหลายวัฒนธรรมมักจะเห็นนามสกุลในตัวอย่างเช่นที่อยู่

ดังนั้นใช้งานstring.Format()โดยเฉพาะอย่างยิ่งหากคุณต้องการให้แอปพลิเคชันของคุณไปทุกที่ที่ภาษาอังกฤษไม่ใช่ภาษาแรก


2
string.Format()พฤติกรรมจะแตกต่างกันในวัฒนธรรมที่แตกต่างกันอย่างไร มันจะยังคงพิมพ์ชื่อแล้วนามสกุลหรือไม่? ดูเหมือนว่าคุณจะต้องคำนึงถึงวัฒนธรรมที่แตกต่างในทั้งสองสถานการณ์ ฉันรู้สึกว่าฉันขาดอะไรบางอย่างที่นี่
Broots Waymb

2
ฉันเห็นด้วยกับ @DangerZone .. จะstring.Format()รู้ได้อย่างไรว่าคุณใช้ชื่อสำหรับที่อยู่ ถ้าstring.Format()เปลี่ยนไป{0} {1}ตามวัฒนธรรมฉันจะถือว่ามันพัง
Alex McMillan

2
ฉันเชื่อว่าประเด็นที่เจเรมีพยายามทำคือในสถานการณ์ที่อธิบายเพื่อสนับสนุนประเทศต่าง ๆ มันอาจจะเหมาะสมที่จะแยกสตริงรูปแบบออกไปยังแหล่งข้อมูลภาษา สำหรับประเทศส่วนใหญ่ที่สตริงจะเป็น "{0} {1}" แต่สำหรับประเทศที่มีนามสกุลแรกคือการดำเนินการทั่วไป (เช่นฮังการี, ฮ่องกง, กัมพูชา, จีน, ญี่ปุ่น, เกาหลี, มาดากัสการ์, ไต้หวัน, เวียดนามและ บางส่วนของอินเดีย) สตริงนั้นจะเป็น "{1} {0}" แทน
Richard J Foster

จริง หรืออย่างละเอียดยิ่งขึ้นให้เพิ่มสตริงรูปแบบเป็นแอตทริบิวต์ของบุคคล ตัวอย่างเช่นฉันต้องการใช้นามสกุลของฉันหลังจากชื่อจริง แต่เพื่อนร่วมงานของฉัน Beng ไม่
Jeremy McGee

14

นี่คือผลลัพธ์ของฉันมากกว่า 100,000 ซ้ำ:

Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took (avg): 0ms - 689 ticks
Console.WriteLine(p.FirstName + " " + p.LastName); took (avg): 0ms - 683 ticks

และนี่คือรหัสม้านั่ง:

Stopwatch s = new Stopwatch();

var p = new { FirstName = "Bill", LastName = "Gates" };

//First print to remove the initial cost
Console.WriteLine(p.FirstName + " " + p.LastName);
Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

int n = 100000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;

for (var i = 0; i < n; i++)
{
    s.Start();
    Console.WriteLine(p.FirstName + " " + p.LastName);
    s.Stop();
    cElapsedMilliseconds += s.ElapsedMilliseconds;
    cElapsedTicks += s.ElapsedTicks;
    s.Reset();
    s.Start();
    Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
    s.Stop();
    fElapsedMilliseconds += s.ElapsedMilliseconds;
    fElapsedTicks += s.ElapsedTicks;
    s.Reset();
}

Console.Clear();

Console.WriteLine("Console.WriteLine(\"{0} {1}\", p.FirstName, p.LastName); took (avg): " + (fElapsedMilliseconds / n) + "ms - " + (fElapsedTicks / n) + " ticks");
Console.WriteLine("Console.WriteLine(p.FirstName + \" \" + p.LastName); took (avg): " + (cElapsedMilliseconds / n) + "ms - " + (cElapsedTicks / n) + " ticks");

ดังนั้นฉันไม่รู้ว่าใครตอบว่าทำเครื่องหมายว่าเป็นคำตอบ :)


ทำไมพื้นหลังเป็นสีน้ำเงินสำหรับคำตอบนี้
user88637

@yossi มันเป็นสีฟ้าเพราะผู้ตอบเหมือนกับผู้
ถาม

9

การต่อสตริงเป็นเรื่องปกติในสถานการณ์ง่าย ๆ เช่นนั้น - มันซับซ้อนกับสิ่งที่ซับซ้อนกว่านั้นแม้แต่ LastName, FirstName ด้วยรูปแบบที่คุณสามารถเห็นได้อย่างรวดเร็วสิ่งที่โครงสร้างสุดท้ายของสตริงจะเป็นเมื่ออ่านโค้ดด้วยการต่อข้อมูลมันแทบจะเป็นไปไม่ได้เลยที่จะแยกแยะผลลัพธ์สุดท้ายได้ทันที (ยกเว้นตัวอย่างง่ายๆเช่นนี้)

สิ่งที่หมายถึงในระยะยาวคือเมื่อคุณกลับมาเปลี่ยนแปลงรูปแบบสตริงของคุณคุณจะมีความสามารถในการปรากฏขึ้นและทำการปรับเปลี่ยนรูปแบบสตริงหรือย่นคิ้วของคุณและเริ่มเคลื่อนไหวไปรอบ ๆ ชนิดของ accessors คุณสมบัติผสมกับข้อความซึ่งมีแนวโน้มที่จะแนะนำปัญหา

หากคุณใช้. NET 3.5 คุณสามารถใช้วิธีการขยายอย่างนี้และทำให้การไหลเวียนของข้อมูลทำได้ง่ายขึ้นโดยปิดไวยากรณ์ของข้อมือดังนี้:

string str = "{0} {1} is my friend. {3}, {2} is my boss.".FormatWith(prop1,prop2,prop3,prop4);

ในที่สุดเมื่อแอปพลิเคชันของคุณมีความซับซ้อนมากขึ้นคุณอาจตัดสินใจว่าจะรักษาสตริงไว้ในแอปพลิเคชันของคุณอย่างถาวรคุณต้องการย้ายไฟล์เหล่านั้นไปยังไฟล์ทรัพยากรเพื่อแปลเป็นภาษาท้องถิ่น นี่จะง่ายกว่ามากถ้าคุณใช้รูปแบบที่ใช้อย่างต่อเนื่องและรหัสของคุณสามารถปรับโครงสร้างให้ใช้สิ่งต่าง ๆ เช่น

string name = String.Format(ApplicationStrings.General.InformalUserNameFormat,this.FirstName,this.LastName);

7

สำหรับการจัดการที่ง่ายมากฉันจะใช้การเรียงต่อกัน แต่เมื่อคุณได้องค์ประกอบที่เกิน 2 หรือ 3 รูปแบบจะกลายเป็น IMO ที่เหมาะสมกว่า

อีกเหตุผลหนึ่งที่ต้องการใช้ String.Format ก็คือสตริง. NET นั้นไม่เปลี่ยนรูปและทำเช่นนี้จะสร้างสำเนาชั่วคราว / ระดับกลางที่น้อยลง


6

ในขณะที่ฉันเข้าใจการตั้งค่ารูปแบบทั้งหมดและเลือกการต่อข้อมูลสำหรับคำตอบแรกของฉันส่วนหนึ่งขึ้นอยู่กับความชอบของฉันเองส่วนหนึ่งของการตัดสินใจของฉันขึ้นอยู่กับความคิดที่ว่าการต่อข้อมูลจะเร็วขึ้น ดังนั้นจากความอยากรู้ฉันทดสอบและผลลัพธ์ก็ส่ายโดยเฉพาะอย่างยิ่งสำหรับสตริงขนาดเล็กเช่นนั้น

ใช้รหัสต่อไปนี้:

    System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch();

    var p = new { FirstName = "Bill", LastName = "Gates" };

    s.Start();
    Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
    s.Stop();
    Console.WriteLine("Console.WriteLine(\"{0} {1}\", p.FirstName, p.LastName); took: " + s.ElapsedMilliseconds + "ms - " + s.ElapsedTicks + " ticks");

    s.Reset();
    s.Start();
    Console.WriteLine(p.FirstName + " " + p.LastName);
    s.Stop();

    Console.WriteLine("Console.WriteLine(p.FirstName + \" \" + p.LastName); took: " + s.ElapsedMilliseconds + "ms - " + s.ElapsedTicks + " ticks");

ฉันได้ผลลัพธ์ดังต่อไปนี้:

Bill Gates
Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took: 2ms - 7280 ticks
Bill Gates
Console.WriteLine(p.FirstName + " " + p.LastName); took: 0ms - 67 ticks

การใช้วิธีการจัดรูปแบบช้ากว่า 100 เท่า !! การต่อข้อมูลไม่แม้แต่จะลงทะเบียนเป็น 1 มิลลิวินาทีด้วยเหตุนี้ฉันจึงออกตัวจับเวลาเห็บด้วยเช่นกัน


2
แต่แน่นอนคุณควรดำเนินการมากกว่าหนึ่งครั้งเพื่อรับการวัด
erikkallen

2
และสูญเสียการโทรไปยัง Console.Writeline () เนื่องจากอยู่นอกเหนือขอบเขตของคำถามหรือไม่
Aidanapword

คุณทดสอบกับผู้สร้างสตริงหรือไม่? ;)
niico

6

การเริ่มต้นจากสตริงการประมาณค่า C # 6.0 สามารถใช้ในการทำสิ่งนี้ซึ่งลดความซับซ้อนของรูปแบบมากยิ่งขึ้น

var name = "Bill";
var surname = "Gates";
MessageBox.Show($"Welcome to the show, {name} {surname}!");

การแสดงออกของสตริง interpolated ดูเหมือนว่าสตริงแม่แบบที่มีการแสดงออก นิพจน์สตริงที่ถูกแทรกจะสร้างสตริงโดยการแทนที่นิพจน์ที่มีอยู่ด้วย ToString represenations ของผลลัพธ์ของนิพจน์

สตริง Interpolated มีประสิทธิภาพคล้ายกับ String.Format แต่ปรับปรุงความสามารถในการอ่านและไวยากรณ์ให้สั้นลงเนื่องจากความจริงที่ว่าค่าและนิพจน์ถูกแทรกในบรรทัด

โปรดอ้างอิงถึงบทความ dotnetperlsเกี่ยวกับการแก้ไขสตริง

หากคุณกำลังมองหาวิธีเริ่มต้นในการจัดรูปแบบสตริงของคุณสิ่งนี้สมเหตุสมผลในแง่ของการอ่านและประสิทธิภาพ (ยกเว้นว่าไมโครวินาทีจะสร้างความแตกต่างในกรณีการใช้งานเฉพาะของคุณ)


5

สำหรับการต่อสตริงพื้นฐานฉันมักจะใช้รูปแบบที่สอง - ง่ายต่อการอ่านและเรียบง่าย อย่างไรก็ตามถ้าฉันทำชุดค่าผสมที่ซับซ้อนมากขึ้นฉันมักจะเลือกใช้ String.Format

String.Format บันทึกในราคาและข้อดี ...

Console.WriteLine("User {0} accessed {1} on {2}.", user.Name, fileName, timestamp);
vs
Console.WriteLine("User " + user.Name + " accessed " + fileName + " on " + timestamp + ".");

มี Charicters เพียงไม่กี่ตัวเท่านั้นที่บันทึกไว้ แต่ฉันคิดว่าในตัวอย่างนี้รูปแบบทำให้สะอาดกว่ามาก


5

การทดสอบที่ดีกว่าคือการดูหน่วยความจำของคุณโดยใช้เคาน์เตอร์หน่วยความจำ Perfmon และ CLR ความเข้าใจของฉันคือเหตุผลทั้งหมดที่คุณต้องการใช้ String.Format แทนที่จะเป็นแค่การเชื่อมโยงสตริงคือเนื่องจากสตริงนั้นไม่เปลี่ยนรูปคุณจึงเป็นภาระของตัวรวบรวมขยะด้วยสตริงชั่วคราวที่จำเป็นต้องเรียกคืนในรอบถัดไป

StringBuilder และ String.Format แม้ว่าหน่วยความจำอาจช้ากว่า แต่มีประสิทธิภาพมากกว่าหน่วยความจำ

อะไรคือสิ่งที่ไม่ดีเกี่ยวกับการเรียงสตริง?


ฉันเห็นด้วย; การดำเนินการกับสตริงทุกครั้งจะสร้างสำเนาใหม่ของสตริง หน่วยความจำขยะทั้งหมดจะถูกเรียกคืนโดยผู้รวบรวมขยะไม่ช้าก็เร็ว ดังนั้นการจัดสรรสตริงจำนวนมากอาจกลับมากัดคุณในภายหลัง
Marnix van Valen

5

โดยทั่วไปฉันชอบแบบเก่าโดยเฉพาะอย่างยิ่งเมื่อสตริงยาวขึ้นมันสามารถอ่านได้ง่ายกว่ามาก

ประโยชน์อีกอย่างคือฉันเชื่อว่าหนึ่งในประสิทธิภาพเนื่องจากจริง ๆ แล้วดำเนินการคำสั่งสร้างสตริงที่ 2 ก่อนที่จะส่งสตริงสุดท้ายไปยังวิธี Console.Write String.Format ใช้ StringBuilder ภายใต้ฝาครอบที่ฉันเชื่อว่าดังนั้นการเชื่อมโยงหลาย ๆ ชุดจะถูกหลีกเลี่ยง

ควรสังเกตว่าถ้าพารามิเตอร์ที่คุณส่งผ่านไปยัง String.Format (และวิธีการอื่น ๆ เช่น Console.Write) เป็นประเภทค่าจากนั้นพวกเขาจะได้รับการบรรจุกล่องก่อนส่งผ่านซึ่งสามารถให้ประสิทธิภาพการทำงานของตัวเอง บล็อกโพสต์เกี่ยวกับเรื่องนี้ที่นี่


1
บล็อกโพสต์นั่นคือตอนนี้ได้ที่: jeffbarnes.net/blog/post/2006/08/08/... ฉันประสบกับตัวแทนไม่เพียงพอที่จะแก้ไข
ริชาร์ดตำหนิ

5

หนึ่งสัปดาห์นับจากวันนี้ 19 สิงหาคม 2558 คำถามนี้จะมีอายุเจ็ด (7) ปี ขณะนี้มีวิธีที่ดีกว่าในการทำเช่นนี้ ในแง่ของการบำรุงรักษาที่ดีขึ้นในขณะที่ฉันยังไม่ได้ทำการทดสอบประสิทธิภาพใด ๆ เมื่อเปรียบเทียบกับสตริงที่ต่อกัน (แต่มันมีความสำคัญในวันนี้หรือไม่? วิธีใหม่ในการทำกับC # 6.0 :

var p = new { FirstName = "Bill", LastName = "Gates" };
var fullname = $"{p.FirstName} {p.LastName}";

คุณลักษณะใหม่นี้ดีกว่า IMO และดีกว่าจริง ๆ ในกรณีของเราเนื่องจากเรามีรหัสที่เราสร้างการสอบถามที่มีค่าขึ้นอยู่กับปัจจัยบางอย่าง ลองนึกภาพหนึ่งข้อสงสัยเมื่อเรามีข้อโต้แย้ง 6 ข้อ ดังนั้นแทนที่จะทำเช่น:

var qs = string.Format("q1={0}&q2={1}&q3={2}&q4={3}&q5={4}&q6={5}", 
    someVar, anotherVarWithLongName, var3, var4, var5, var6)

ในสามารถเขียนได้เช่นนี้และง่ายต่อการอ่าน:

var qs=$"q1={someVar}&q2={anotherVarWithLongName}&q3={var3}&q4={var4}&q5={var5}&q6={var6}";

แท้จริงแล้ววิธีใหม่ของ C # 6.0 นั้นดีกว่าทางเลือกก่อนหน้า - อย่างน้อยจากมุมมองที่อ่านได้
ฟิลิปป์

ถูกตัอง. และยังปลอดภัยกว่าเพราะคุณไม่ต้องกังวลว่าวัตถุใดจะไปที่ดัชนี (ตัวยึด) เนื่องจากคุณจะวางวัตถุที่คุณต้องการให้เป็นโดยตรง
von v.

BTW เรียกจริง ๆ ว่า Format (อย่างน้อยก็กับ Roslyn)
ฟิลิปป์

BTW สิ่งที่ผู้โพสต์นี้อ้างถึงเรียกว่า "การสอดแทรกสตริง" และแก้ไขที่อื่นในกระทู้นี้
CShark

4
  1. การจัดรูปแบบเป็นวิธี“. NET” ในการดำเนินการ เครื่องมือ refactoring บางตัว (Refactor! for one) จะเสนอให้ refactor โค้ดสไตล์ concat เพื่อใช้สไตล์การจัดรูปแบบ
  2. การจัดรูปแบบนั้นง่ายต่อการปรับให้เหมาะสมสำหรับคอมไพเลอร์ (แม้ว่าอันที่สองอาจจะถูกปรับโครงสร้างใหม่ให้ใช้วิธี 'Concat' ซึ่งเร็วมาก)
  3. การจัดรูปแบบมักจะชัดเจนในการอ่าน (โดยเฉพาะกับการจัดรูปแบบ "แฟนซี")
  4. การจัดรูปแบบหมายถึงการเรียก '. ToString' โดยนัยสำหรับตัวแปรทั้งหมดซึ่งดีสำหรับการอ่าน
  5. ตาม "Effective C #" การใช้งาน. NET 'WriteLine' และ 'Format' จะทำให้เกิดความสับสนพวกเขาจะปรับค่าประเภททั้งหมดโดยอัตโนมัติ (ซึ่งไม่ดี) “ Effective C #” แนะนำให้ทำการโทร '. ToString' อย่างชัดเจนซึ่ง IMHO เป็นการหลอกลวง (ดูการโพสต์ของ Jeff )
  6. ในขณะนี้คำแนะนำประเภทการจัดรูปแบบจะไม่ถูกตรวจสอบโดยคอมไพเลอร์ซึ่งส่งผลให้เกิดข้อผิดพลาดขณะทำงาน อย่างไรก็ตามสิ่งนี้สามารถแก้ไขได้ในรุ่นอนาคต

4

ฉันเลือกตามความสามารถในการอ่าน ฉันชอบตัวเลือกรูปแบบเมื่อมีข้อความรอบตัวแปร ในตัวอย่างนี้:

Console.WriteLine("User {0} accessed {1} on {2}.", 
                   user.Name, fileName, timestamp);

คุณเข้าใจความหมายแม้ไม่มีชื่อตัวแปรในขณะที่ concat เต็มไปด้วยคำพูดและเครื่องหมาย + และทำให้ฉันสับสน:

Console.WriteLine("User " + user.Name + " accessed " + fileName + 
                  " on " + timestamp + ".");

(ฉันยืมตัวอย่างของไมค์เพราะฉันชอบ)

หากสตริงรูปแบบไม่ได้มีความหมายมากโดยไม่มีชื่อตัวแปรฉันต้องใช้ concat:

   Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

ตัวเลือกการจัดรูปแบบทำให้ฉันอ่านชื่อตัวแปรและจับคู่กับตัวเลขที่เกี่ยวข้อง ตัวเลือก concat ไม่จำเป็นต้องใช้ ฉันยังสับสนกับเครื่องหมายคำพูดและเครื่องหมาย + แต่ทางเลือกนั้นแย่กว่า ทับทิม?

   Console.WriteLine(p.FirstName + " " + p.LastName);

ผลการดำเนินงานที่ชาญฉลาดผมคาดว่าตัวเลือกรูปแบบที่จะช้าลงแล้ว concat ตั้งแต่รูปแบบต้องสตริงที่จะแยกวิเคราะห์ ฉันจำไม่ได้ว่าต้องเพิ่มประสิทธิภาพการเรียนการสอนแบบนี้ แต่ถ้าฉันทำฉันจะดูstringวิธีการเช่นConcat()และJoin()และ

ข้อได้เปรียบอื่น ๆ ที่มีรูปแบบคือสตริงรูปแบบสามารถใส่ในไฟล์กำหนดค่า มีประโยชน์มากกับข้อความแสดงข้อผิดพลาดและข้อความ UI


4

ฉันจะใช้ String.Format แต่ฉันจะมีสตริงรูปแบบในไฟล์ทรัพยากรเพื่อให้สามารถแปลเป็นภาษาอื่นได้ การใช้ concat สตริงอย่างง่ายไม่อนุญาตให้คุณทำเช่นนั้น เห็นได้ชัดว่าถ้าคุณไม่จำเป็นต้อง จำกัด วงสตริงตัวเองนี่ไม่ใช่เหตุผลที่จะต้องคิด มันขึ้นอยู่กับว่าสตริงนั้นมีไว้เพื่ออะไร

หากมันจะปรากฏต่อผู้ใช้ฉันจะใช้ String.Format เพื่อให้ฉันสามารถ จำกัด วงถ้าฉันต้องการ - และFxCopจะสะกดตรวจสอบให้ฉันในกรณี :)

ถ้ามันมีตัวเลขหรือสิ่งอื่นใดที่ไม่ใช่สตริง (เช่นวันที่) ฉันจะใช้ String.Format เพราะมันช่วยให้ฉันควบคุมการจัดรูปแบบได้มากขึ้นได้มากขึ้น

หากเป็นการสร้างแบบสอบถามเช่น SQL ฉันจะใช้Linq Linq

หากการต่อสตริงภายในลูปฉันจะใช้StringBuilderเพื่อหลีกเลี่ยงปัญหาด้านประสิทธิภาพ

ถ้าเป็นผลลัพธ์ที่ผู้ใช้จะไม่เห็นและจะไม่ส่งผลต่อประสิทธิภาพที่ฉันใช้ String.Format เพราะฉันยังคงใช้มันอยู่แล้วและฉันก็คุ้นเคยกับมัน :)


3

หากคุณกำลังจัดการกับบางสิ่งที่จำเป็นต้องอ่านง่าย (และนี่คือรหัสส่วนใหญ่) ฉันจะใช้โอเปอเรเตอร์โอเวอร์โหลดเวอร์ชัน UNLESS:

  • รหัสจะต้องมีการดำเนินการหลายล้านครั้ง
  • คุณกำลังทำข้อตกลงหลายตัน (มากกว่า 4 เป็นตัน)
  • รหัสถูกกำหนดเป้าหมายไปยัง Compact Framework

อย่างน้อยสองสถานการณ์ฉันจะใช้ StringBuilder แทน


3

หากคุณตั้งใจจะแปลผลลัพธ์ให้เป็นสตริง String.Format เป็นสิ่งจำเป็นเนื่องจากภาษาธรรมชาติที่แตกต่างกันอาจไม่มีข้อมูลอยู่ในลำดับเดียวกัน


2

ฉันคิดว่าสิ่งนี้ขึ้นอยู่กับความซับซ้อนของผลลัพธ์ ฉันมักจะเลือกสถานการณ์ที่เหมาะสมที่สุดในขณะนั้น

เลือกเครื่องมือที่เหมาะสมตามงาน: D แล้วแต่ว่าจะสะอาดที่สุด!


2

ฉันชอบอันดับที่สองเช่นกัน แต่ไม่มีข้อโต้แย้งที่สมเหตุสมผลในขณะนี้เพื่อสนับสนุนตำแหน่งนั้น


2

ทำได้ดีนี่!

เพิ่งเพิ่ม

        s.Start();
        for (var i = 0; i < n; i++)
            result = string.Concat(p.FirstName, " ", p.LastName);
        s.Stop();
        ceElapsedMilliseconds = s.ElapsedMilliseconds;
        ceElapsedTicks = s.ElapsedTicks;
        s.Reset();

และมันก็เร็วขึ้น (ฉันเดาว่า string.Catcat ถูกเรียกทั้งสองตัวอย่าง แต่อันแรกต้องใช้การแปลบางอย่าง)

1000000 x result = string.Format("{0} {1}", p.FirstName, p.LastName); took: 249ms - 3571621 ticks
1000000 x result = (p.FirstName + " " + p.LastName); took: 65ms - 944948 ticks
1000000 x result = string.Concat(p.FirstName, " ", p.LastName); took: 54ms - 780524 ticks

2
ใช้เวลาเท่ากันstring.Concat(...)ทุกประการนับตั้งแต่การรวมสตริงที่อิงตามตัวดำเนินการถูกแปลโดยคอมไพเลอร์ที่จะเรียก มันทำในระหว่างการรวบรวมดังนั้นจึงไม่มีผลกระทบต่อประสิทธิภาพการทำงาน หากคุณรันการทดสอบหลายครั้งหรือเรียกใช้การทดสอบตัวอย่างขนาดใหญ่คุณจะเห็นว่าพวกเขาเหมือนกัน
Allon Guralnek

2

เนื่องจากฉันไม่คิดว่าคำตอบที่นี่จะครอบคลุมทุกสิ่งฉันจึงต้องการเพิ่มเติมเล็กน้อยที่นี่

Console.WriteLine(string format, params object[] pars) โทร string.Formatโทรเครื่องหมาย '+' หมายถึงการต่อสตริงเข้าด้วยกัน ฉันไม่คิดว่าสิ่งนี้จะเกี่ยวข้องกับสไตล์เสมอไป ฉันมักจะผสมสองสไตล์ขึ้นอยู่กับบริบทของฉัน

คำตอบสั้น ๆ

การตัดสินใจที่คุณกำลังเผชิญนั้นเกี่ยวข้องกับการจัดสรรสตริง ฉันจะพยายามทำให้มันง่าย

บอกว่าคุณมี

string s = a + "foo" + b;

หากคุณดำเนินการสิ่งนี้จะมีการประเมินดังนี้:

string tmp1 = a;
string tmp2 = "foo" 
string tmp3 = concat(tmp1, tmp2);
string tmp4 = b;
string s = concat(tmp3, tmp4);

tmpที่นี่ไม่ได้เป็นตัวแปรในท้องถิ่น แต่เป็นเพียงชั่วคราวสำหรับ JIT (มันถูกผลักลงบนกอง IL) หากคุณกดสตริงบนสแต็ก (เช่นldstrใน IL สำหรับตัวอักษร) คุณจะใส่การอ้างอิงไปยังตัวชี้สตริงบนสแต็ก

ช่วงเวลาที่คุณโทร concatการอ้างอิงนี้กลายเป็นปัญหาเนื่องจากไม่มีการอ้างอิงสตริงที่มีทั้งสองสตริง ซึ่งหมายความว่า. NET จำเป็นต้องจัดสรรบล็อกหน่วยความจำใหม่แล้วกรอกด้วยสองสาย เหตุผลนี้เป็นปัญหาเนื่องจากการจัดสรรค่อนข้างแพง

คำถามใดที่เปลี่ยนเป็น: คุณจะลดจำนวนconcatการปฏิบัติงานได้อย่างไร

ดังนั้นคำตอบคร่าวๆคือstring.Formatสำหรับ> 1 concats '+' จะใช้ได้ดีสำหรับ 1 concat และถ้าคุณไม่สนใจเกี่ยวกับการเพิ่มประสิทธิภาพไมโครประสิทธิภาพstring.Formatจะทำงานได้ดีในกรณีทั่วไป

หมายเหตุเกี่ยวกับวัฒนธรรม

แล้วมีบางสิ่งที่เรียกว่าวัฒนธรรม ...

string.Formatช่วยให้คุณสามารถใช้CultureInfoในการจัดรูปแบบของคุณ ตัวดำเนินการอย่างง่าย '+' ใช้วัฒนธรรมปัจจุบัน

นี่เป็นคำพูดที่สำคัญอย่างยิ่งหากคุณกำลังเขียนรูปแบบไฟล์และ f.ex doubleค่าที่คุณ 'เพิ่ม' ให้กับสตริง บนเครื่องที่แตกต่างกันคุณอาจจบลงด้วยสตริงแตกต่างกันถ้าคุณไม่ได้ใช้กับอย่างชัดเจนstring.FormatCultureInfo

F.ex. พิจารณาสิ่งที่เกิดขึ้นหากคุณเปลี่ยน '.' สำหรับ ',' ในขณะที่เขียนไฟล์ค่าคั่นด้วยจุลภาคของคุณ ... ในภาษาดัตช์ตัวคั่นทศนิยมเป็นเครื่องหมายจุลภาคดังนั้นผู้ใช้ของคุณอาจได้รับความประหลาดใจ 'ตลก'

คำตอบที่ detailled เพิ่มเติม

หากคุณไม่ทราบขนาดที่แน่นอนของสตริงไว้ก่อนหน้านี้ควรใช้นโยบายเช่นนี้เพื่อกำหนดขนาดบัฟเฟอร์ที่คุณใช้โดยรวม พื้นที่หย่อนถูกเติมเต็มครั้งแรกหลังจากนั้นข้อมูลจะถูกคัดลอก

การเติบโตหมายถึงการจัดสรรบล็อกหน่วยความจำใหม่และคัดลอกข้อมูลเก่าไปยังบัฟเฟอร์ใหม่ บล็อกเก่าของหน่วยความจำนั้นจะถูกปล่อยออกมา คุณจะได้รับบรรทัดล่าง ณ จุดนี้: การเติบโตคือการดำเนินการที่มีราคาแพง

วิธีปฏิบัติที่เป็นประโยชน์ที่สุดในการทำเช่นนี้คือการใช้นโยบายภาพรวม นโยบายที่พบบ่อยที่สุดคือการรวม overallocate buffers ในระดับ 2 แน่นอนคุณต้องฉลาดกว่านี้เล็กน้อย (เนื่องจากไม่มีเหตุผลที่จะเติบโตจาก 1,2,4,8 หากคุณรู้ว่าคุณต้องการ 128 ตัวอักษร ) แต่คุณจะได้รับภาพ นโยบายช่วยให้มั่นใจว่าคุณไม่ต้องการการดำเนินการที่มีราคาแพงมากเกินไปที่ฉันอธิบายไว้ข้างต้น

StringBuilderเป็นคลาสที่ overallocates บัฟเฟอร์พื้นฐานเป็นกำลังสอง string.Formatใช้StringBuilderภายใต้ประทุน

สิ่งนี้ทำให้การตัดสินใจของคุณเป็นการแลกเปลี่ยนพื้นฐานระหว่าง overallocate และผนวก (-multiple) (วัฒนธรรม w / wo) หรือเพียงแค่จัดสรรและผนวก


1

โดยส่วนตัวแล้วตัวที่สองที่ทุกอย่างที่คุณใช้อยู่ในลำดับที่ตรงนั้นจะถูกส่งออกในขณะที่คนแรกที่คุณต้องตรงกับ {0} และ {1} กับ var ที่เหมาะสมซึ่งเป็นเรื่องง่ายที่จะสับสน

อย่างน้อยก็ไม่ได้แย่เหมือน C ++ sprintf ซึ่งถ้าคุณทำผิดประเภทตัวแปรสิ่งทั้งหมดจะระเบิด

นอกจากนี้เนื่องจากข้อที่สองเป็นแบบอินไลน์และไม่จำเป็นต้องทำการค้นหาและแทนที่สิ่งทั้งหมด {0} สิ่งหลังควรจะเร็วกว่า ... แม้ว่าฉันจะไม่ทราบแน่นอน


1

ฉันชอบอันแรกจริง ๆ เพราะเมื่อมีตัวแปรมากมายที่สอดแทรกข้อความดูเหมือนง่ายต่อการอ่านสำหรับฉัน นอกจากนี้ยังง่ายต่อการจัดการกับคำพูดเมื่อใช้สตริงรูปแบบ (), เอ่อรูปแบบ นี่คือการวิเคราะห์ที่ดีของการเรียงต่อสตริง


1

ฉันไปเส้นทาง string.Format () เสมอ ความสามารถในการเก็บรูปแบบในตัวแปรเช่นตัวอย่างของ Nathan เป็นข้อได้เปรียบ ในบางกรณีฉันอาจต่อท้ายตัวแปร แต่มีมากกว่าหนึ่งตัวแปรที่ถูกต่อกันฉัน refactor เพื่อใช้การจัดรูปแบบ


1

โอ้และเพื่อความสมบูรณ์ต่อไปนี้เป็นเพียงไม่กี่เห็บเร็วกว่าการต่อข้อมูลปกติ:

Console.WriteLine(String.Concat(p.FirstName," ",p.LastName));

1

รูปแรก (รูปแบบ) ดูดีกว่าสำหรับฉัน สามารถอ่านได้มากขึ้นและคุณไม่ได้สร้างวัตถุสตริงชั่วคราวเพิ่มเติม


1

ฉันอยากรู้ว่า StringBuilder ยืนอยู่กับการทดสอบเหล่านี้ ผลลัพธ์ด้านล่าง ...

class Program {
   static void Main(string[] args) {

      var p = new { FirstName = "Bill", LastName = "Gates" };

      var tests = new[] {
         new { Name = "Concat", Action = new Action(delegate() { string x = p.FirstName + " " + p.LastName; }) },
         new { Name = "Format", Action = new Action(delegate() { string x = string.Format("{0} {1}", p.FirstName, p.LastName); }) },
         new { Name = "StringBuilder", Action = new Action(delegate() {
            StringBuilder sb = new StringBuilder();
            sb.Append(p.FirstName);
            sb.Append(" ");
            sb.Append(p.LastName);
            string x = sb.ToString();
         }) }
      };

      var Watch = new Stopwatch();
      foreach (var t in tests) {
         for (int i = 0; i < 5; i++) {
            Watch.Reset();
            long Elapsed = ElapsedTicks(t.Action, Watch, 10000);
            Console.WriteLine(string.Format("{0}: {1} ticks", t.Name, Elapsed.ToString()));
         }
      }
   }

   public static long ElapsedTicks(Action ActionDelg, Stopwatch Watch, int Iterations) {
      Watch.Start();
      for (int i = 0; i < Iterations; i++) {
         ActionDelg();
      }
      Watch.Stop();
      return Watch.ElapsedTicks / Iterations;
   }
}

ผล:

Concat: 406 เห็บ
Concat: 356 เห็บ
Concat: 411 เห็บ
Concat: 299 เห็บ
Concat: 266 เห็บ
รูปแบบ: 5269 เห็บ
รูปแบบ: 954 เห็บ
รูปแบบ: 1004 เห็บ
รูปแบบ: เห็บ 984
รูปแบบ: 974 เห็บ
StringBuilder: 629 เห็บ
StringBuilder: 484 เห็บ
StringBuilder: 482 เห็บ
StringBuilder: 508 เห็บ
StringBuilder: 504 เห็บ

1

ตามเนื้อหาเตรียม MCSD Microsoft แนะนำให้ใช้ตัวดำเนินการ + เมื่อต้องจัดการกับการเรียงต่อกันจำนวนน้อยมาก (อาจเป็น 2 ถึง 4) ฉันยังไม่แน่ใจว่าทำไม แต่เป็นสิ่งที่ต้องพิจารณา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.