Tôi có nên sử dụng .ToString () khi nối các biến số nguyên và chuỗi trong C # không?


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

Tôi có nên sử dụng:

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

hoặc là

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

Có nên sử dụng ToString()khi nối stringintkhông?


6
Trong a + "" + b + ""hoặc "" + a + b + "", nó không thành vấn đề: đó là tất cả các chuỗi nối. Trong a + b + ""đó có vấn đề: abđược thêm vào đầu tiên.
Tim S.

4
Lưu ý bên lề: Trong VB.NET, sự mơ hồ này được tránh bằng cách sử dụng toán tử nối chuỗi rõ ràng : "Expression: " + asẽ đưa ra lỗi thời gian biên dịch (với Tùy chọn Strict On), "Expression: " & asẽ thực hiện nối chuỗi.
Heinzi

Mã đầu tiên sẽ dẫn đến quyền anh (int đến Int32), mã thứ hai thì không. Cái thứ hai rõ ràng là nhanh hơn.
Bảng chữ cái ngẫu nhiên

Câu trả lời:


33

ToString sử dụng

Không, bạn không nên sử dụng ToStringở đây.

Nối chuỗi tự động biến đổi các chuỗi không thành chuỗi, có nghĩa là hai biến thể của bạn gần giống nhau:

Khi một hoặc cả hai toán hạng thuộc kiểu chuỗi, các toán tử bổ sung được xác định trước sẽ ghép nối biểu diễn chuỗi của toán hạng.

Nguồn: Đặc tả ngôn ngữ C #: Toán tử bổ sung, MSDN .

Mặt khác, cái đầu tiên (không có ToString):

  • Viết ngắn hơn
  • Là ngắn hơn để đọc,
  • Dễ bảo trì hơn và:
  • cho thấy chính xác ý định của tác giả: nối chuỗi.

Vì vậy, thích cái đầu tiên.

Dưới mui xe

Điều cũng thú vị là để xem những gì xảy ra dưới mui xe. Một trong những cách để xem nó là xem mã IL trong LINQPad. Chương trình này:

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

được dịch sang IL sau:

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

Thấy System.String.Concatchưa Điều đó có nghĩa là mã gốc có thể được viết giống như vậy, nó chuyển thành chính xác 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);
}

Khi bạn đọc tài liệu vềstring.Concat(object[]) , bạn có thể biết rằng:

Phương pháp này concatenates từng đối tượng trong args bằng cách gọi parameterless ToStringphương pháp của đối tượng đó; nó không thêm bất kỳ dấu phân cách nào

Điều này có nghĩa ToStringlà dư thừa. Cũng thế:

String.Empty được sử dụng thay cho bất kỳ đối tượng null nào trong mảng.

Mà xử lý độc đáo trường hợp một số toán hạng là null (xem chú thích 1).

Trong khi trong ví dụ trước, phép nối được dịch thành string.Concat, người ta cũng nên làm nổi bật tối ưu hóa trình biên dịch:

var a = "Hello " + "World";

được dịch thành:

ldstr       "Hello World"
stloc.0

Mặt khác:

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

được dịch thành:

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

Các lựa chọn thay thế khác

Tất nhiên có nhiều cách khác để nối các biểu diễn chuỗi của các đối tượng trong C #.

  1. StringBuilderđược sử dụng khi bạn cần thực hiện nhiều thao tác nối và giúp giảm số lượng chuỗi trung gian được tạo. Quyết định xem bạn nên sử dụng một StringBuilderhoặc một cách ghép thông thường có thể không dễ dàng. Sử dụng một hồ sơ hoặc tìm kiếm các câu trả lời có liên quan trên Stack Overflow.

    Việc sử dụng StringBuildercó một nhược điểm lớn là làm cho mã khó đọc và bảo trì. Đối với các trường hợp đơn giản như câu hỏi trong câu hỏi của bạn, StringBuilderkhông chỉ có hại cho khả năng đọc mã, mà còn vô dụng về mặt hiệu suất.

  2. string.Join nên được sử dụng khi bạn cần thêm dấu phân cách.

    Rõ ràng, không bao giờ sử dụng string.Joinvới một dấu phân cách trống để nối chuỗi.

  3. string.Formatcó thể được sử dụng khi tạo khuôn mẫu chuỗi được ưu tiên để nối chuỗi. Một trong những trường hợp bạn có thể thích đó là khi tin nhắn có thể được bản địa hóa, như được đề xuất trong câu trả lời của kunthet.

    Việc sử dụng string.Formatcó một số nhược điểm khiến nó không phù hợp với các trường hợp đơn giản như của bạn:

    • Với các trình giữ chỗ "{0}" đơn giản, thường không rõ tham số nào đi đâu. Nó thường xuyên bị nhầm lẫn đảo ngược các tham số hoặc quên một tham số. May mắn thay, C # 6 cuối cùng đã giới thiệu phép nội suy chuỗi giải quyết vấn đề này.

    • Hiệu suất thời gian chạy có thể giảm. Tất nhiên, đừng cho rằng string.Formatluôn luôn chậm hơn. Nếu hiệu suất có vấn đề, hãy đo hai cách tiếp cận và xác định phương pháp nào nhanh hơn dựa trên kết quả thực tế của bạn thay vì giả định.

    • Mã này hơi dài để viết, đọc lâu hơn và khó bảo trì hơn, mặc dù điều này cực kỳ nhỏ và không nên làm phiền bạn quá nhiều.


Sự khác biệt xuất hiện khi một trong các đối tượng là null. Không có ToString, a nullđược thay thế bằng một chuỗi rỗng. Với ToString, một NullReferenceExceptionlà ném.


1
Vì chính xác lý do này (hành vi không thể đoán trước), các chuỗi nối với nhau +được coi là thực tiễn xấu trong hầu hết các ngôn ngữ. Trong trường hợp này tôi sẽ sử dụng string.Concat, trong nhiều trường hợp string.Formatlà tốt hơn. Nó chắc chắn không phải là Pythonic để sử dụng +, và vì PEP 3101 %không được khuyến khích str.format.
Arda Xi

2
Là thay thế một chuỗi trống để nullthực sự "xử lý nó độc đáo"? Chà, nó không tệ như "tiếp tục lỗi tiếp theo" ...
Ded repeatator

Dưới mui xe, nếu bạn ghép nối mà không gọi .ToString (), quyền anh sẽ xảy ra ..., và Concat(object[])sẽ được sử dụng thay vì Concat(string[]). Vì vậy, "string " + inó không thực sự giống với"string " + i.ToString()
Bảng chữ cái ngẫu nhiên

@RandomAlphabets: điểm hợp lệ. Tuy nhiên, sự khác biệt chỉ đơn giản là vị trí của ToString(): mã OP trong một trường hợp, System.String.Concattriển khai trong trường hợp khác. Vì vậy, câu trả lời vẫn còn hiệu lực: đừng viết mã không có lợi.
Arseni Mourzenko

15

Thay vào đó, bạn nên sử dụng chuỗi định dạng. Định dạng số của bạn thành biểu diễn chuỗi hoặc bản địa hóa dễ dàng hơn. ví dụ:

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

Thêm thông tin về MSDN .

Tuy nhiên, trình định dạng chuỗi ít đọc hơn (và cũng có thể là hiệu suất) so với nối chuỗi.


6
Quan tâm để giải thích tại sao tùy chọn này là tốt hơn?
Kỹ sư thế giới

@WorldEngineer: Tôi đã cập nhật lời giải thích.
kunthet

12
Tôi không biết về những người khác, nhưng tôi thực sự thấy điều này dễ đọc hơn. Có lẽ bởi vì tôi lớn lên với C trong đó s [n] printf là lựa chọn thực tế duy nhất cho loại mã này.
Jules

2
Nhưng cách này đưa ra ba nguồn sai lầm thay vì một. Khi bạn thêm một cái gì đó vào chuỗi, bạn 1) phải thay đổi chuỗi định dạng, 2) không được quên thêm tham số mới trong danh sách, 3) cố gắng chọn vị trí chính xác trong danh sách nên đặt tham số mới.
Ruslan

2
Chỉ muốn hòa nhập và cho bạn biết về tính năng nội suy chuỗi sắp tới trong C # 6 .. Bạn sẽ viết "Biểu thức: \ {a} + \ {b} = \ {sum}" để có kết quả tương tự. codeproject.com/Articles/846566/
hy

-2

Nếu bạn sử dụng +phép nối, chính nó sử dụng String.Concatphương thức. Chuỗi chính nó không phơi bày một toán tử +.

ví dụ:

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

được biên dịch thành:

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

Nếu bạn gọi trực tiếp ToString, nó sẽ tránh đấm bốc và gọi Concat(string, string)quá tải. Do đó ToStringcuộc gọi sẽ hiệu quả hơn một chút mặc dù không đủ quan trọng. Bạn tốt hơn nên đi với ví dụ bạn cảm thấy dễ đọc hơn.


2
điều này dường như chỉ lặp lại các điểm được thực hiện và giải thích trong câu trả lời trước : "Nối chuỗi tự động biến đổi các chuỗi không thành chuỗi ..."
gnat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.