2010-02-15 25 views
6

Tôi tự hỏi nếu mã này ...Một StringBuilder được khởi tạo với một chuỗi chứa chính xác (chỉ) đủ không gian cho chuỗi đó?

StringBuilder sb = new StringBuilder("Please read the following messages."); 

... khởi sb với một bộ đệm chính xác lớn như chuỗi truyền cho constructor. Một mặt, điều này có vẻ là điều hợp lý nhất. Mặt khác, nó dường như đánh bại mục đích của lớp học StringBuilder cho một trong những cách sử dụng phổ biến nhất của nó, đó là cung cấp khả năng biến đổi để làm cho các phụ thêm lặp lại hiệu quả hơn. (Cuộc gọi đầu tiên để Append, nếu câu trả lời cho câu hỏi của tôi là "có", sẽ đòi hỏi sb để thay đổi kích thước của chính nó.)

Sau đó, một lần nữa, tôi cho rằng người ta có thể xem đây là tương tự như các nhà xây dựng cho List<T> mà phải mất một IEnumerable<T> làm tham số. Có thể giả định trong trường hợp này là bạn không lập kế hoạch trên gắn thêm nhiều, nhưng thay vào đó là thao tác những gì đã có ở đó. Các nghiên cứu thực tế duy nhất tôi đã thực hiện trên này là để kiểm tra các MSDN documentation on StringBuilder, mà không cung cấp một câu trả lời (nó nói constructor khởi tạo dụ "sử dụng chuỗi quy định," nhưng không chỉ cách chuỗi được sử dụng).


EDIT: Vì vậy, nó được "thực hiện cụ thể" ... Điều này có vẻ không lạ với bất cứ ai khác? Ý tôi là, mục đích của lớp StringBuilder là cung cấp cách thay thế để thực hiện nhiều thao tác trên string, tạo ra một tấn các trường hợp bất biến string trên đường đi; do đó, nó cho hiệu suất . Tôi cảm thấy hành vi của nhà xây dựng này nên được chỉ định, để nhà phát triển có thể đưa ra quyết định sáng suốt về cách sử dụng nó bất kể nền tảng.

Ý tôi là, được Microsoft triển khai theo cách nhất định; họ có thể dễ dàng đặt nó vào tài liệu (buộc các triển khai khác phải tuân theo). Chỉ là một nguồn cá nhân của sự bối rối ...

Trả lời

5

Đó là chi tiết triển khai mà bạn không cần phải lo lắng.Tuy nhiên, bằng cách sử dụng .NET reflector và tìm trong quá trình (chuỗi, int32, int32, int32) quá tải của hàm tạo (mà các nhà thầu khác gọi), chúng ta có thể thấy rằng nó chọn công suất là bội số của 16 (lớn hơn kế tiếp so với yêu cầu) kích thước)

Sửa

Trên thực tế, đó là 16 x 2^n, với giá trị của "n" chọn là kích thước lớn nhất tiếp theo

+0

Tốt cuộc gọi - tôi j chúng tôi đã tự kiểm tra điều này và đạt được kết luận tương tự (bằng cách kiểm tra thuộc tính 'Dung lượng' sau khi khởi tạo ... bằng cách nào đó điều này không xảy ra với tôi cho đến sau khi tôi đăng câu hỏi). –

+1

... nhưng bạn không nên dựa vào điều này. Nếu bạn quan tâm đủ về công suất cần thiết để đăng câu hỏi trên Stack Overflow, bạn chỉ nên sử dụng một trong những tình trạng quá tải mà bạn có thể chỉ định nó. Toàn bộ mục đích của "thực hiện cụ thể" có nghĩa là nó có thể thay đổi trong tương lai. Đừng dựa vào hành vi không có giấy tờ. –

+0

@Lasse - Ồ, đồng ý. Tôi sẽ không ủng hộ * dựa vào * về chi tiết này. (Và đấu tranh để suy nghĩ làm thế nào bạn có thể kết thúc dựa vào thực tế này) –

4

Kiểm tra thành viên dung lượng của StringBuilder.

Từ MSDN:

Các StringBuilder động phân bổ thêm không gian khi cần thiết và tăng công suất cho phù hợp. Vì lý do hiệu suất, một StringBuilder có thể cấp phát bộ nhớ nhiều hơn mức cần thiết. Lượng bộ nhớ được cấp phát cụ thể cho việc triển khai thực hiện.

2

các constructor bạn liên quan đến có lẽ là bị xích vào các StringBuilder(String, Int32, Int32, Int32):

public StringBuilder(
    string value, 
    int startIndex, 
    int length, 
    int capacity 
) 

Vì vậy, đối với chuỗi, nó có thể sẽ đi qua: string, 0, string.Length, string.Length. Hoặc một cái gì đó tương tự có ý nghĩa trong bối cảnh StringBuilder.

+0

Âm thanh như (từ câu trả lời của Damien, mà ông đã sử dụng Reflector) đầu tiên của bạn "có lẽ" là đúng, và thứ hai của bạn đã gần (thực sự là sức mạnh tiếp theo của 16, như trái ngược với chỉ 'string.Length'). –

+0

... và "sức mạnh tiếp theo 16", ý tôi là "gấp 16 lần sức mạnh tiếp theo của 2". Tôi không nghĩ rằng sau 16 nó đi thẳng đến 256 và sau đó đến 4096 (tôi ngu ngốc). –

1

Các constructor mà cuối cùng được gọi là:

// "Please read the following messages.".Length = 35 
public StringBuilder(string value, int startIndex, int length, int capacity) 
public StringBuilder("Please read the following messages.", 0, 
     "Please read the following messages.".Length, 16) 

(Đây là gì mà các câu trả lời khác không cung cấp, và chỉ là từ phản xạ)
Nếu công suất là nhỏ hơn chiều dài của chuỗi, mà nó là trong trường hợp này:

while (capacity < length) 
{ 
    capacity *= 2; 
    if (capacity < 0) 
    { 
     capacity = length; 
     break; 
    } 
} 

trong Mono, các nhà xây dựng StringBuilder(string val) phân bổ năng lực để int.MaxValue cho đến khi một append xảy ra.

Câu trả lời thực sự nằm trong phương pháp mà kết thúc lên được gọi nội bộ trong CLR, nơi chiều dài là năng lực:

[MethodImpl(MethodImplOptions.InternalCall)] 
private static extern string FastAllocateString(int length); 

tôi không thể tìm thấy nguồn cho điều này trong tuy nhiên SSCLI phiên bản Mono (\ mono \ metadata \ object.c) thực hiện nó như thế này:

mono_string_new_size (MonoDomain *domain, gint32 len) 
{ 
    MonoString *s; 
    MonoVTable *vtable; 
    size_t size = (sizeof (MonoString) + ((len + 1) * 2)); 

... 
} 

đó là kích thước tính bằng byte của một đối tượng MonoString, cộng với chiều dài lần 2.

+0

Thông tin này đến từ đâu? Bạn đang sử dụng Windows, Mono hay ...? Dường như những phát hiện của bạn về khả năng ban đầu của «StringBuilder' khác với Damien (và của tôi). –

+0

@Dan - một lỗi nhỏ với 0x10 :) –

+0

Mã bạn đã cung cấp là hữu ích, nhưng xung đột với những gì bạn đã nói! "Hàm tạo sử dụng độ dài chuỗi của bạn làm dung lượng" - điều này không đúng; rằng 'while' loop tăng gấp đôi' dung lượng' cho đến khi 'capacity> = length'; do đó, nó sẽ là giá trị bắt đầu của nó (mà dường như là 16) lần một sức mạnh của 2. –

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