ฉันควรใช้. ToString () เมื่อเชื่อมสตริงและตัวแปรจำนวนเต็มใน C # หรือไม่


19
int a = 1;
int b = 2;
int sum = a + b;
string expression = "Expression: " + a + " + " + b + " = " + sum;
Console.WriteLine(expression); //displays Expression 1 + 2 = 3

ฉันควรใช้:

string expression = "Expression: " + a + " + " + b + " = " + sum;

หรือ

string expression = "Expression: " + a.ToString() + " + " + b.ToString() + " = " + result.ToString();

มันแนะนำให้ใช้ToString()เมื่อเชื่อมต่อstringและint?


6
ในa + "" + b + ""หรือ"" + a + b + ""มันไม่สำคัญ: มันคือทั้งหมดที่เรียงต่อกันเป็นสตริง ในa + b + ""มันไม่สำคัญ: aและbมีการเพิ่มเป็นครั้งแรก
Tim S.

4
หมายเหตุด้านข้าง: ใน VB.NET ความคลุมเครือนี้จะถูกหลีกเลี่ยงโดยการมีตัวดำเนินการเรียงสตริงที่ชัดเจน: "Expression: " + aจะโยนข้อผิดพลาดเวลาคอมไพล์ (ด้วย Option Strict On) "Expression: " & aจะทำการต่อสตริง
Heinzi

รหัสแรกจะส่งผลให้เกิดการชกมวย (int ถึง Int32), รหัสที่สองไม่ได้ เห็นได้ชัดว่าสองเร็วกว่า
ตัวอักษรสุ่ม

คำตอบ:


33

ToString การใช้

ไม่คุณไม่ควรใช้ToStringที่นี่

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

เมื่อหนึ่งหรือทั้งสองตัวถูกดำเนินการเป็นสตริงประเภทตัวดำเนินการเพิ่มที่กำหนดไว้ล่วงหน้าเชื่อมโยงการแสดงสตริงของตัวถูกดำเนินการ

ที่มา: C # ภาษาสเปก: ผู้ประกอบการนอกจากนี้ MSDN

ในทางกลับกันคนแรก (ไม่รวมToString):

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

ดังนั้นเลือกอันแรก

ภายใต้ประทุน

สิ่งที่น่าสนใจก็คือดูว่าเกิดอะไรขึ้นภายใต้ประทุน อีกวิธีหนึ่งที่จะเห็นมันคือการดูรหัส IL ภายใน LINQPad โปรแกรมนี้:

void Main()
{
    var a = 3;
    var b = " Hello";
    var c = a + b;
    Console.WriteLine(c);
}

แปลเป็นภาษา IL ดังต่อไปนี้:

IL_0001:  ldc.i4.3    
IL_0002:  stloc.0     // a
IL_0003:  ldstr       " Hello"
IL_0008:  stloc.1     // b
IL_0009:  ldloc.0     // a
IL_000A:  box         System.Int32
IL_000F:  ldloc.1     // b
IL_0010:  call        System.String.Concat
IL_0015:  stloc.2     // c
IL_0016:  ldloc.2     // c
IL_0017:  call        System.Console.WriteLine

เห็นSystem.String.Concatไหม นั่นหมายความว่าโค้ดต้นฉบับสามารถเขียนได้เช่นเดียวกันซึ่งแปลเป็น IL เดียวกัน:

void Main()
{
    var a = 3;
    var b = " Hello";
    var c = string.Concat(a, b); // This is the line which was changed.
    Console.WriteLine(c);
}

เมื่อคุณอ่านเอกสารประกอบของstring.Concat(object[])คุณอาจเรียนรู้ว่า:

วิธีการเชื่อมแต่ละวัตถุในargsโดยการเรียกToStringวิธีการแบบไม่มีพารามิเตอร์ของวัตถุนั้น มันไม่ได้เพิ่มตัวคั่นใด ๆ

ซึ่งหมายความว่าToStringซ้ำซ้อน นอกจากนี้:

String.Empty ถูกใช้แทนวัตถุใด ๆ null ในอาร์เรย์

ซึ่งจัดการอย่างกรณีที่ตัวถูกดำเนินการบางอย่างเป็นโมฆะ (ดูเชิงอรรถ 1)

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

var a = "Hello " + "World";

แปลเป็น:

ldstr       "Hello World"
stloc.0

ในทางกลับกัน:

var a = string.Concat("Hello ", "World");

แปลเป็น:

ldstr       "Hello "
ldstr       "World"
call        System.String.Concat
stloc.0

ทางเลือกอื่น ๆ

มีวิธีการอื่น ๆ ที่จะเชื่อมโยงการแทนค่าสตริงของวัตถุใน C #

  1. StringBuilderจะใช้เมื่อคุณต้องทำการดำเนินการเรียงต่อกันจำนวนมากและช่วยลดจำนวนสายอักขระตัวกลางที่สร้างขึ้น การตัดสินใจว่าคุณควรใช้StringBuilderหรือการต่อข้อมูลแบบธรรมดาอาจไม่ใช่เรื่องง่าย ใช้ profiler หรือค้นหาคำตอบที่เกี่ยวข้องใน Stack Overflow

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

  2. string.Join ควรใช้เมื่อคุณต้องการเพิ่มตัวคั่น

    เห็นได้ชัดว่าstring.Joinห้ามใช้กับตัวคั่นที่ว่างเปล่าเพื่อเชื่อมสตริงเข้าด้วยกัน

  3. string.Formatสามารถใช้เมื่อการสร้างสตริงสตริงต้องการการเชื่อมต่อสายอักขระ หนึ่งในกรณีที่คุณอาจต้องการคือเมื่อข้อความอาจมีการแปลตามคำแนะนำโดย kunthet

    การใช้string.Formatมีข้อบกพร่องหลายประการซึ่งทำให้ไม่เหมาะสำหรับกรณีง่ายๆเช่นคุณ:

    • ด้วยตัวยึดง่าย "{0}" มักจะไม่ชัดเจนว่าพารามิเตอร์ตัวไหนไป บ่อยครั้งที่การย้อนกลับพารามิเตอร์ผิดพลาดหรือลืมอย่างใดอย่างหนึ่ง โชคดีที่C # 6 ในที่สุดก็แนะนำการแก้ไขสตริงซึ่งแก้ปัญหานี้ได้

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

    • รหัสนี้ยาวกว่าการเขียนเล็กน้อยอ่านและอ่านได้ยากขึ้นแม้ว่าจะน้อยมากและไม่ควรรบกวนคุณมากเกินไป


null¹ความแตกต่างที่ปรากฏขึ้นเมื่อหนึ่งของวัตถุที่เป็น หากไม่มีToStringa nullจะถูกแทนที่ด้วยสตริงว่าง ด้วยToStringการNullReferenceExceptionโยน


1
ด้วยเหตุผลนี้ (พฤติกรรมที่คาดเดาไม่ได้) การเชื่อมสตริงที่มีการ+พิจารณาว่าไม่เหมาะสมในภาษาส่วนใหญ่ ในกรณีนี้ฉันจะใช้string.Concatในหลายกรณีstring.Formatดีกว่า มันไม่แน่นอน Pythonic กับการใช้งาน+และตั้งแต่ PEP 3101 เป็นกำลังใจเป็นอย่างดีในความโปรดปรานของ% str.format
Arda Xi

2
การแทนที่สตริงว่างสำหรับnull"การจัดการเป็นอย่างดี" จริงหรือไม่? ก็ไม่เลวเหมือน "เมื่อเกิดข้อผิดพลาดต่อไป" ...
Deduplicator

ภายใต้ประทุนถ้าคุณเชื่อมโดยไม่ต้องโทร .ToString () มวยที่จะเกิดขึ้น ... และจะนำมาใช้แทนConcat(object[]) Concat(string[])ดังนั้นจึง"string " + iไม่เหมือนกันกับ"string " + i.ToString()
ตัวอักษรแบบสุ่ม

@RandomAlphabets: จุดที่ถูกต้อง อย่างไรก็ตามความแตกต่างนั้นก็คือที่ตั้งของToString(): รหัสของ OP ในกรณีหนึ่งSystem.String.Concatการติดตั้งในอีกกรณีหนึ่ง ดังนั้นคำตอบยังคงใช้ได้: อย่าเขียนโค้ดที่ไม่มีประโยชน์
Arseni Mourzenko

15

คุณควรใช้ตัวจัดรูปแบบสตริงแทน การจัดรูปแบบหมายเลขของคุณเป็นการแสดงสตริงหรือการแปลเป็นภาษาท้องถิ่นได้ง่ายกว่า เช่น:

string expression = string.Format("Expression: {0} + {1} = {2}", a, b, sum);

ข้อมูลเพิ่มเติมเกี่ยวกับMSDN

อย่างไรก็ตามตัวจัดรูปแบบสตริงสามารถอ่านได้น้อยกว่า (และอาจรวมถึงประสิทธิภาพ) กว่าการต่อสตริง


6
สนใจที่จะอธิบายว่าทำไมตัวเลือกนี้ถึงดีกว่า
วิศวกรโลก

@WorldEngineer: ฉันอัพเดตคำอธิบาย
kunthet

12
ฉันไม่รู้เกี่ยวกับคนอื่น แต่จริง ๆ แล้วฉันคิดว่าสิ่งนี้สามารถอ่านได้มากขึ้น อาจเป็นเพราะฉันโตมาพร้อมกับ C ซึ่ง s [n] printf เป็นตัวเลือกที่เหมือนจริงเพียงอย่างเดียวสำหรับโค้ดประเภทนี้
จูลส์

2
แต่วิธีนี้ให้แหล่งที่มาของความผิดพลาดสามข้อแทนที่จะเป็นแหล่งเดียว เมื่อคุณเพิ่มบางสิ่งลงในสตริงคุณ 1) ต้องเปลี่ยนสตริงรูปแบบ 2) ไม่ลืมที่จะเพิ่มพารามิเตอร์ใหม่ในรายการ 3) พยายามเลือกจุดที่ถูกต้องในรายการที่ควรใส่พารามิเตอร์ใหม่
Ruslan

2
เพียงแค่ต้องการพูดสอดและแจ้งให้คุณทราบเกี่ยวกับคุณลักษณะการแก้ไขสตริงที่จะเกิดขึ้นใน C # 6 .. คุณจะเขียน "Expression: \ {a} + \ {b} = \ {sum}" เพื่อให้ได้ผลลัพธ์เดียวกัน codeproject.com/Articles/846566/…
cwap

-2

หากคุณใช้การ+ต่อข้อมูลตัวมันเองจะใช้String.Concatวิธีการ สายอักขระไม่เปิดเผยตัวดำเนินการ +

ตัวอย่างเช่น:

int i = 10;
string str = "hello" + i;

ถูกรวบรวมเป็น:

int i = 10;
object o1 = "hello";
object o2 = i; // Note boxing
string str = string.Concat(o1, o2);

หากคุณโทรโดยตรงToStringมันจะหลีกเลี่ยงการชกมวยและเรียกการConcat(string, string)โอเวอร์โหลด ดังนั้นการToStringโทรจะมีประสิทธิภาพมากขึ้นเล็กน้อยแม้ว่าจะไม่เพียงพอ คุณควรอ่านตัวอย่างที่คุณรู้สึกดีกว่า


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