2009-05-07 40 views
17

Nếu tôi đang xây dựng một chuỗi bằng cách sử dụng một đối tượng StringBuilder trong một phương thức, sẽ có ý nghĩa:Giá trị trả về String hoặc StringBuilder?

Trả về đối tượng StringBuilder và để mã gọi điện thoại gọi ToString()?

return sb; 

HOẶC Trả lại chuỗi bằng cách gọi ToString().

return sb.ToString(); 

Tôi đoán nó tạo sự khác biệt nếu chúng tôi trả về các chuỗi nhỏ hoặc lớn. Điều gì sẽ phù hợp trong mỗi trường hợp? Cảm ơn trước.

Chỉnh sửa: Tôi không có kế hoạch sửa đổi thêm chuỗi trong mã gọi điện, nhưng điểm tốt Colin Burnett.

Chủ yếu, việc trả lại đối tượng StringBuilder hoặc chuỗi có hiệu quả hơn không? Một tham chiếu đến chuỗi được trả lại, hoặc một bản sao?

Trả lời

21

Trả về StringBuilder nếu bạn định sửa đổi chuỗi, nếu không thì trả về chuỗi. Đây là một câu hỏi API.

Về hiệu quả. Vì đây là một câu hỏi mơ hồ/chung chung mà không có bất kỳ chi tiết cụ thể nào thì tôi nghĩ rằng có thể thay đổi so với bất biến là quan trọng hơn hiệu suất. Mutability là một vấn đề API cho phép các đối tượng có thể sửa đổi của API của bạn. Độ dài chuỗi không liên quan đến điều này.

Điều đó nói. Nếu bạn nhìn vào StringBuilder.ToString với Reflector:

public override string ToString() 
{ 
    string stringValue = this.m_StringValue; 
    if (this.m_currentThread != Thread.InternalGetCurrentThread()) 
    { 
     return string.InternalCopy(stringValue); 
    } 
    if ((2 * stringValue.Length) < stringValue.ArrayLength) 
    { 
     return string.InternalCopy(stringValue); 
    } 
    stringValue.ClearPostNullChar(); 
    this.m_currentThread = IntPtr.Zero; 
    return stringValue; 
} 

Bạn có thể thấy nó có thể tạo một bản sao nhưng nếu bạn sửa đổi nó với StringBuilder sau đó nó sẽ tạo một bản sao sau đó (đây là những gì tôi có thể nói điểm m_currentThread là bởi vì Append kiểm tra điều này và sẽ sao chép nó nếu nó không khớp với chuỗi hiện tại).

Tôi đoán kết thúc này là nếu bạn không sửa đổi StringBuilder thì bạn không sao chép chuỗi và độ dài không liên quan đến hiệu quả (trừ khi bạn nhấn thứ 2 nếu).

CẬP NHẬT

System.String là một lớp học có nghĩa là nó là một loại tài liệu tham khảo (như trái ngược với kiểu giá trị) để "chuỗi foo;" về cơ bản là một con trỏ. (Khi bạn truyền một chuỗi vào một phương thức, nó truyền con trỏ, chứ không phải bản sao.) System.String có thể thay đổi bên trong mscorlib nhưng không thay đổi bên ngoài nó, đó là cách StringBuilder có thể thao tác một chuỗi.

Vì vậy, khi ToString() được gọi là nó trả về đối tượng chuỗi nội bộ của nó bằng cách tham chiếu. Tại thời điểm này, bạn không thể sửa đổi nó vì mã của bạn không có trong mscorlib. Bằng cách đặt trường m_currentThread thành 0 thì bất kỳ thao tác nào khác trên StringBuilder sẽ làm cho nó sao chép đối tượng chuỗi để nó có thể được sửa đổi không sửa đổi đối tượng chuỗi mà nó trả về trong ToString(). Hãy xem xét điều này:

StringBuilder sb = new StringBuilder(); 
sb.Append("Hello "); 

string foo = sb.ToString(); 

sb.Append("World"); 

string bar = sb.ToString(); 

Nếu StringBuilder không tạo bản sao vào cuối foo sẽ là "Hello World" vì StringBuilder đã sửa đổi nó. Nhưng vì nó đã tạo ra một bản sao thì foo vẫn chỉ là "Hello" và thanh là "Hello World".

Điều đó có làm rõ toàn bộ thông tin trả lại/tham chiếu không?

+0

@SkippyFire đang hỏi về hiệu quả. –

+0

-1. Nếu bạn tiếp tục sửa đổi chuỗi, nó sẽ được sửa đổi thêm trong phương thức. Điều gì nếu phương pháp này được gọi từ nhiều nơi và logic thao tác chuỗi thay đổi? Nó sẽ không được tốt để có cập nhật logic ở nhiều nơi –

+1

Nick, bạn đang tách lông. Nếu đây là một lớp và một phương thức riêng tư, bạn có thể vượt qua StringBuilder với nhiều phương thức để xây dựng chuỗi cuối cùng. Bạn có thể làm cùng một điều mà mỗi phương thức trả về một chuỗi và nối chúng lại. SkippyFire không cụ thể về cách sử dụng nó. Điều này khá đơn giản: nếu bạn cần có thể thay đổi được, sau đó trả về có thể thay đổi, nếu bạn không cần tắt tiếng thì không thể trả lại được. –

5

Tôi không nghĩ hiệu suất nên là yếu tố trong câu hỏi này. Dù bằng cách nào đó ai đó sẽ gọi sb.ToString() vì vậy bạn sẽ thực hiện cú đánh một nơi nào đó.

Câu hỏi quan trọng hơn là mục đích của phương pháp và mục đích là gì. Nếu phương thức này là một phần của trình xây dựng, bạn có thể trả về trình tạo chuỗi. Nếu không, tôi sẽ trả về một chuỗi.

Nếu đây là một phần của API công khai, tôi sẽ dựa vào việc trả về chuỗi thay vì trình tạo.

+0

Câu hỏi hiệu quả, sau đó, là nếu bạn đang sửa đổi chuỗi nhiều hơn thì tốt hơn nên có nó ở dạng có thể thay đổi (ví dụ, StringBuilder) để tránh sao chép vào một StringBuilder mới để sửa đổi nó. Chỉ vì một nơi nào đó xuống dòng bạn sẽ gọi ToString không có nghĩa là bạn không muốn tránh sao chép trung gian. –

+1

@Colin Burnett, xét về mặt hiệu năng, nếu cần có khả năng thay đổi, trả về StringBuilder là một giải pháp thiết thực, nhưng nó không phải là một giải pháp tốt. Nó là thích hợp hơn để viết lại người gọi để hỗ trợ một mô hình xây dựng đối tượng hoàn toàn và ngăn chặn việc xây dựng chuỗi cho một cuộc gọi duy nhất. Có hai hạn chế để trả về StringBuilder, đầu tiên, nó kết hợp bạn với một chi tiết thực hiện. Thứ hai, nó tránh xa việc cho phép một cách tiếp cận OOP tốt, điều này sẽ cản trở khả năng tồn tại của giải pháp như một API (và khóa bạn đến một thực hiện thủ tục). –

+0

Michael, điểm duy nhất của tôi trong nhận xét đó là "ai đó sẽ gọi sb.ToString() "là thiếu điểm sao chép trung gian sẽ ảnh hưởng đến hiệu suất. Đôi khi, có, bạn cũng có thể muốn lấy hit vì lợi ích của việc có một API tốt hơn hoặc được thúc đẩy để tìm một giải pháp khác hơn là" chuỗi hoặc StringBuilder ". –

3

Tôi sẽ nói phương thức sẽ trả về sb.ToString(). Nếu logic xung quanh việc tạo đối tượng StringBuilder() sẽ thay đổi trong tương lai, nó có ý nghĩa với tôi rằng nó được thay đổi trong phương thức không có trong mỗi kịch bản gọi phương thức và sau đó tiếp tục làm điều gì đó khác

0

Nếu bạn cần phải nối thêm nhiều thứ vào chuỗi và sử dụng chức năng liên quan đến trình xây dựng chuỗi khác, trả về trình xây dựng chuỗi. Nếu không, nếu bạn chỉ sử dụng chuỗi, hãy trả về chuỗi.

Có những cân nhắc kỹ thuật khác, nhưng đó là mối quan tâm cấp cao nhất.

1

Tùy thuộc vào những gì bạn định làm với đầu ra. Tôi sẽ trả lại một chuỗi cá nhân. Bằng cách đó, nếu bạn cần thay đổi phương thức xuống đường để không sử dụng trình tạo chuỗi, bạn có thể không bị mắc kẹt với điều đó dưới dạng giá trị trả lại.

Khi suy nghĩ về nó cho thời điểm này, câu trả lời là rõ ràng hơn nhiều. Câu hỏi đặt câu hỏi sẽ được trả lại thực sự là câu trả lời cho câu hỏi. Đối tượng trả về phải là một chuỗi. Lý do là nếu bạn đang đặt câu hỏi, "Có lý do nào để trả về đối tượng StringBuilder khi một chuỗi sẽ làm gì không?" thì câu trả lời là không. Nếu có một lý do, sau đó trả về chuỗi sẽ được ra khỏi câu hỏi, bởi vì các phương pháp và tài sản của stringbuilder là cần thiết.

1

Tôi nghĩ rằng nó phụ thuộc vào những gì bạn đang làm với chuỗi khi nó rời khỏi phương thức. Nếu bạn sẽ tiếp tục phụ thêm vào nó thì bạn có thể cân nhắc việc trả về một trình xây dựng chuỗi để có hiệu quả cao hơn. Nếu bạn luôn gọi .ToString() trên đó thì bạn nên làm điều đó bên trong phương thức để đóng gói tốt hơn.

1

Tôi sẽ trả lại string trong hầu hết các trường hợp, đặc biệt nếu phương thức là một phần của API công khai.

Một ngoại lệ sẽ là nếu phương pháp của bạn chỉ là một phần của quy trình "xây dựng" riêng tư lớn hơn và mã gọi điện sẽ thực hiện các thao tác tiếp theo. Trong trường hợp đó, tôi có thể cân nhắc việc trả lại một số StringBuilder.

1

Kể từ khi bạn sẽ không sửa đổi nó nữa

return sb.ToString(); 

nên hiệu quả nhất

1

Return các sb.ToString(). Phương pháp của bạn nên tập trung vào những thứ trong tay (Trong trường hợp này xây dựng cho tôi một chuỗi) và không được trả lại để được xử lý IMO hơn nữa, bạn có thể gặp phải tất cả các vấn đề với nó không được xử lý.

3

StringBuilder là chi tiết triển khai phương pháp của bạn. Bạn nên trả về chuỗi cho đến khi nó trở thành một vấn đề hiệu suất, tại thời điểm đó bạn nên khám phá một mẫu khác (như visitor Pattern) có thể giúp bạn giới thiệu sự hướng dẫn và bảo vệ bạn khỏi các quyết định triển khai nội bộ.

Chuỗi luôn được lưu trữ trong heap, vì vậy bạn sẽ có tham chiếu trả lại nếu kiểu trả về là chuỗi. Tuy nhiên, bạn không thể đếm được trên hai chuỗi giống nhau để có các tham chiếu giống hệt nhau. Nói chung, nó an toàn để nghĩ về một chuỗi như thể nó là một loại giá trị mặc dù nó thực sự là một kiểu tham chiếu.

+1

+1 để biết chi tiết triển khai –

0

Phương pháp này được đưa ra một nhiệm vụ cụ thể và cần được hoàn thành và trả lại kết quả đã hoàn thành mà không cần xử lý thêm. Chỉ trả về StringBuilder khi bạn thực sự cần nó. Trong trường hợp đó cũng thêm một cái gì đó vào tên phương thức để chỉ ra rằng bạn đang trả về một cái gì đó đặc biệt.

Các vấn đề liên quan