2011-12-13 28 views
27

Tôi đang cố gắng hiểu tại sao string.Emptyreadonly chứ không phải là const. Tôi đã xem this Bài đăng nhưng tôi không hiểu nhận xét mà Microsoft đã viết về nó. Như Jon Skeet wrote trong một nhận xét "Tôi không biết - nó không có ý nghĩa với tôi, phải trung thực ..."Có nghĩa là gây nhầm lẫn nhận xét ở trên "string.Empty" trong nguồn .NET/BCL?

Shared Source Common Language Infrastructure 2.0 Release. string.cs là trong sscli20 \ clr \ src \ bcl \ system \ string.cs

// The Empty constant holds the empty string value. 
//We need to call the String constructor so that the compiler doesn't mark this as a literal. 
//Marking this as a literal would mean that it doesn't show up as a field which we can access 
//from native. 
public static readonly String Empty = ""; 

Tôi không thể nhìn thấy ở đây bất kỳ cuộc gọi constructor String và hơn nữa, nó đánh dấu là đen - ""

Có thể ai đó vui lòng giải thích cho tôi bằng văn bản thuần túy, Ý kiến ​​có ý nghĩa gì và tại sao là string.Emptyreadonly chứ không phải là const?


Cập nhật:
Eric Lippert nhận xét về bởi bây giờ là một deleted answer:

tôi hỏi một trong những C# cũ giờ trong bữa ăn trưa về vấn đề này và anh ta đã không nhớ cụ thể tại sao quyết định này là thực hiện, nhưng phỏng đoán rằng nó có liên quan đến việc thực tập.

+7

Có lẽ đó là một trong những nhận xét có ý nghĩa tại một thời điểm, nhưng sau đó mã đã được thay đổi và nó không còn có ý nghĩa ... không phải là tôi đã từng làm điều đó hay bất cứ điều gì ... * còi khi anh bước đi * –

+41

"Tại sao nó không phải là một const" - bởi vì sau đó bạn không thể vui chơi làm 'typeof (string) .GetField (" Empty "). SetValue (null, null);' hoặc 'typeof (string) .GetField ("Trống") SetValue (null, ""); '- mwahahah; mwaaaahahahahahahhh; MWWWWAAAAAHAHAHAHAHAHH! –

+2

@MarcGravell, Eric Lippert ở đâu khi cần thiết. "Giúp tôi siêu nhân ..." – gdoron

Trả lời

14

Phần quan trọng không phải là những gì xảy ra trong lớp này, nhưng điều gì xảy ra, khi một lớp khác sử dụng (và liên kết tới) nó. Hãy để tôi giải thích với một ví dụ khác:

Giả sử bạn có một Assembly1.dll chứa một lớp tuyên bố

public static const int SOME_ERROR_CODE=0x10; 
public static readonly int SOME_OTHER_ERROR_CODE=0x20; 

và lớp khác tiêu thụ ví dụ này

public int TryFoo() { 
    try {foo();} 
    catch (InvalidParameterException) {return SOME_ERROR_CODE;} 
    catch (Exception) { return SOME_OTHER_ERROR_CODE;} 
    return 0x00; 
} 

Bạn biên dịch lớp học của bạn vào Assembly2.dll và liên kết nó với Assembly1.dll, như mong đợi, phương pháp của bạn sẽ trở 0x10 trên các thông số không hợp lệ, 0x20 về các lỗi khác, 0x00 trên thành công.

Đặc biệt, nếu bạn tạo Assembly3.exe chứa một cái gì đó giống như

int errorcode=TryFoo(); 
if (errorcode==SOME_ERROR_CODE) bar(); 
else if (errorcode==SOME_OTHER_ERROR_CODE) baz(); 

Nó sẽ làm việc như mong đợi (Sau khi được liên kết chống lại Assembly1.dll và Assembly2.dll)

Bây giờ nếu bạn nhận được một mới phiên bản của Assembly1.dll, có

public const int SOME_ERROR_CODE=0x11; 
public readonly int SOME_OTHER_ERROR_CODE=0x21; 

Nếu bạn biên dịch lại Assembly3.exe và liên kết đoạn cuối cùng với Assembly1.dll mới và không thay đổi Assembly2.dll, nó sẽ ngừng làm việc như mong đợi:

bar() sẽ KHÔNG được gọi một cách chính xác: Assembly2.dll nhớ Literal 0x20, mà không phải là 0x21 đen tương tự mà Assembly3.exe đọc ra khỏi Assembly1.dll

baz () sẽ được gọi chính xác: Cả Assembly2.dll và Assembly3.exe đều tham chiếu đến SYMBOL REFERENCE được gọi là SOME_OTHER_ERROR_CODE, trong cả hai trường hợp được giải quyết bởi phiên bản hiện tại của Assembly1.dll, do đó trong cả hai trường hợp là 0x21.

Tóm tắt: const tạo một LITERAL, một readonly tạo một SYMBOL REFERENCE.

LITERALS là nội bộ trong khuôn khổ và không thể được marshalled và do đó được sử dụng bởi mã gốc.

Vì vậy

public static readonly String Empty = ""; 

tạo ra một symbol reference (resovled tại thời điểm sử dụng đầu tiên bởi một cuộc gọi đến String cosntuctor), mà có thể sắp đặt một do đó được sử dụng từ nguồn gốc, trong khi

public static const String Empty = ""; 

sẽ tạo ra một chữ, không thể.

+1

những lợi ích mà string.Empty không phải là "nhớ" nó sẽ không được thay đổi. const có thể ổn, phải không? – gdoron

+0

Tôi nghi ngờ nó là về marshalling: Các bình luận mã nói về việc có thể gọi nó từ bản địa, và literals không phải là marshallable. –

+0

Tôi muốn hiểu tại sao chữ không phải là marshallable ... Có gì khác nhau giữa một chữ và một tham chiếu trả về cùng một giá trị? –