Tại sao String.Empty không đổi?


188

Trong .Net tại sao String.Empty chỉ đọc thay vì hằng số? Tôi chỉ tự hỏi liệu có ai biết lý do đằng sau quyết định đó không.


5
Câu hỏi này có thể giải quyết câu hỏi này, câu trả lời ngắn gọn là, không ai biết ...
gdoron đang hỗ trợ Monica

Vâng, +1 cho phản hồi của Eric Lippert, cảm ơn!
ngày

Đặc biệt được cho rằng Decimal.Zero là const (từ góc độ người dùng là ...)
Hamish Grubijan

Câu trả lời:


147

Lý do static readonlyđược sử dụng thay vì constlà do sử dụng với mã không được quản lý, như được Microsoft chỉ ra ở đây trong Bản phát hành cơ sở hạ tầng ngôn ngữ chung 2.0 . Các tập tin để xem xét là sscli20\clr\src\bcl\system\string.cs.

Hằng số rỗng giữ giá trị chuỗi rỗng. Chúng ta cần gọi hàm tạo String để trình biên dịch không đánh dấu đây là chữ.

Đánh dấu điều này là một nghĩa đen có nghĩa là nó không hiển thị như một lĩnh vực mà chúng ta có thể truy cập từ bản địa.

Tôi tìm thấy thông tin này từ bài viết tiện dụng này tại CodeProject .


Tôi thực sự đánh giá cao nếu bạn có thể giải thích nhận xét này (vì Jon Skeet không thể ...) xem tại đây: stackoverflow.com/questions/8462697/
mẹo

2
@gdoron: Tôi đoán (và đó là phỏng đoán) là đây. Khi một giá trị được định nghĩa là một chữ (một hằng số), giá trị của nó được chèn vào những nơi mà nó được tham chiếu trong khi khi nó không được định nghĩa là một chữ, nguồn của giá trị được tham chiếu và giá trị thực được lấy trong thời gian chạy. Tôi nghi ngờ rằng cái sau có thể đảm bảo rằng việc sắp xếp chuỗi đúng xảy ra giữa nguồn gốc và .NET khi chạy - nếu nó là một nghĩa đen, có lẽ trình biên dịch gốc sẽ cần phải kéo giá trị bằng chữ nào đó vào mã gốc của nó, có lẽ không phải là khả thi. Đây là tất cả các phỏng đoán về phần của tôi, mặc dù.
Jeff Yates

7
Điều đó có nghĩa là người ta phải sử dụng "", thay vì chuỗi.Empty cho các giá trị tham số mặc định trong các phương thức. Mà hơi khó chịu.
nicodemus13

17
"" có thể trông giống như một sai lầm, trong khi chuỗi .Empty thể hiện ý định có chủ ý
Christopher Stevenson

3
@JeffYates Tôi muốn nói thêm rằng thực tế là nó không nhất quán đã gây phiền nhiễu. Mọi người sẽ thấy phần còn lại của mã và tự hỏi "tại sao anh ta lại sử dụng" "ở đây thay vì String.Empty?". Tôi nghiêm túc xem xét việc không sử dụng String.Emptynữa vì lý do đó một mình.
julealgon

24

Tôi nghĩ rằng có rất nhiều nhầm lẫn và phản ứng xấu ở đây.

Trước hết, constcác trường là staticthành viên ( không phải thành viên thể hiện ).

Kiểm tra phần 10.4 Các hằng số của đặc tả ngôn ngữ C #.

Mặc dù các hằng số được coi là thành viên tĩnh, một khai báo không đổi không yêu cầu cũng không cho phép sửa đổi tĩnh.

Nếu public constcác thành viên là tĩnh, người ta không thể xem xét rằng một hằng số sẽ tạo ra một Đối tượng mới.

Vì điều này, các dòng mã sau đây thực hiện chính xác điều tương tự đối với việc tạo ra một Đối tượng mới.

public static readonly string Empty = "";
public const string Empty = "";

Dưới đây là một lưu ý từ Microsoft giải thích sự khác biệt giữa 2:

Từ khóa chỉ đọc khác với từ khóa const. Một trường const chỉ có thể được khởi tạo tại phần khai báo của trường. Một trường chỉ đọc có thể được khởi tạo tại khai báo hoặc trong hàm tạo. Do đó, các trường chỉ đọc có thể có các giá trị khác nhau tùy thuộc vào hàm tạo được sử dụng. Ngoài ra, trong khi trường const là hằng số thời gian biên dịch, trường chỉ đọc có thể được sử dụng cho hằng số thời gian chạy, ...

Vì vậy, tôi thấy rằng câu trả lời hợp lý duy nhất ở đây là của Jeff Yates.


+1 cho các từ loại và làm rõ về thông số C # trên const và chỉ đọc tĩnh.
Jeff Yates

17
Đọc lại điều này, tôi không đồng ý const stringstatic readonly stringlàm điều tương tự. Các giá trị Const được thay thế trong mã được liên kết trong khi các giá trị chỉ đọc tĩnh được tham chiếu. Nếu bạn có constthư viện A được thư viện B sử dụng, thư viện B sẽ thay thế tất cả các tham chiếu đến constbiến đó bằng giá trị bằng chữ của nó; nếu biến đó là static readonlythay vào đó, nó sẽ được tham chiếu và giá trị của nó được xác định khi chạy.
Jeff Yates

3
Quan điểm của Jeff rất quan trọng khi tham khảo các thư viện. Nếu bạn biên dịch lại A và phân phối lại, mà không biên dịch lại B , B vẫn sẽ sử dụng các giá trị cũ.
Mark Sowul

4
String.Empty read only instead of a constant?

Nếu bạn tạo bất kỳ chuỗi nào không đổi , thì trình biên dịch sẽ được thay thế bằng chuỗi thực sự ở mọi nơi bạn gọi nó và bạn điền mã của mình với cùng một chuỗi và khi mã chạy cũng cần đọc lại chuỗi đó từ bộ nhớ khác dữ liệu.

Nếu bạn để chuỗi của bạn chỉ đọc ở một nơi vì nó là String.Emptychương trình, thì chương trình chỉ giữ cùng một chuỗi ở một nơi và đọc nó hoặc tham chiếu đến nó - giữ dữ liệu trong bộ nhớ tối thiểu.

Ngoài ra nếu bạn biên dịch bất kỳ dll nào bằng String.Empty dưới dạng const và vì bất kỳ lý do nào thay đổi String.Empty, thì dll đã biên dịch sẽ không hoạt động giống nhau nữa, bởi vì costtạo mã bên trong để thực sự giữ một bản sao của chuỗi trên mỗi cuộc gọi.

Xem mã này ví dụ:

public class OneName
{
    const string cConst = "constant string";
    static string cStatic = "static string";
    readonly string cReadOnly = "read only string";

    protected void Fun()
    {
        string cAddThemAll ;

        cAddThemAll = cConst;
        cAddThemAll = cStatic ;
        cAddThemAll = cReadOnly;    
    }
}

sẽ đến bởi trình biên dịch như:

public class OneName
{
    // note that the const exist also here !
    private const string cConst = "constant string";
    private readonly string cReadOnly;
    private static string cStatic;

    static OneName()
    {
        cStatic = "static string";
    }

    public OneName()
    {
        this.cReadOnly = "read only string";
    }

    protected void Fun()
    {
        string cAddThemAll ;

        // look here, will replace the const string everywhere is finds it.
        cAddThemAll = "constant string";
        cAddThemAll = cStatic;
        // but the read only will only get it from "one place".
        cAddThemAll = this.cReadOnly;

    }
}

và cuộc gọi lắp ráp

        cAddThemAll = cConst;
0000003e  mov         eax,dword ptr ds:[09379C0Ch] 
00000044  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cStatic ;
00000047  mov         eax,dword ptr ds:[094E8C44h] 
0000004c  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cReadOnly;
0000004f  mov         eax,dword ptr [ebp-3Ch] 
00000052  mov         eax,dword ptr [eax+0000017Ch] 
00000058  mov         dword ptr [ebp-44h],eax 

Chỉnh sửa: Sửa lỗi chính tả


Vì vậy, điều này có nghĩa là chuỗi const phải luôn được khởi tạo với lớp chứa const đó? Có vẻ như tốt hơn là sử dụng tĩnh chỉ đọc sau đó.
berserker

@theberserker tốt hơn, nhưng bạn có tất cả các tùy chọn để sử dụng.
Aristos

> sau đó dll đã biên dịch sẽ không hoạt động giống nhau nữa, vì chi phí làm cho mã bên trong thực sự giữ một bản sao của chuỗi trên mỗi cuộc gọi. @Aristos Điều đó không hoàn toàn đúng. Sau khi mã được biên dịch, "bản sao" của chuỗi sẽ được tham chiếu trong khối văn bản của tệp thực thi và tất cả mã sẽ chỉ tham chiếu cùng một khối bộ nhớ. Những gì bạn đã trích dẫn trong bước thứ hai của bạn chỉ đơn giản là một bước trung gian.
Peter Dolkens

@ user1533523 cảm ơn bạn đã lưu ý - Tôi sẽ thực hiện một bài kiểm tra khi tôi có thời gian để kiểm tra điều này
Aristos

Làm thế nào bạn có được mã lắp ráp đó? C # không biên dịch để lắp ráp!
jv110

0

Câu trả lời này tồn tại cho mục đích lịch sử.

Nguyên văn:

Bởi vì Stringlà một lớp và do đó không thể là một hằng số.

Thảo luận mở rộng:

Rất nhiều hộp thoại hữu ích đã được bổ sung để xem xét câu trả lời này, và thay vì xóa nó, nội dung này được sao chép trực tiếp:

Trong .NET, chuỗi (không giống như trong Java) và Chuỗi hoàn toàn giống nhau. Và vâng, bạn có thể có các hằng chuỗi theo nghĩa đen trong .NET - DrJokepu ngày 3 tháng 2 '09 lúc 16:57

Bạn đang nói rằng một Class không thể có hằng số? - StingyJack ngày 3 tháng 2 'lúc 16:58

Có, các đối tượng phải sử dụng chỉ đọc. Chỉ structs có thể làm hằng số. Tôi nghĩ rằng khi bạn sử dụng stringthay vì Stringtrình biên dịch sẽ thay đổi const thành chỉ đọc cho bạn. Tất cả để làm với việc giữ cho các lập trình viên C hạnh phúc. - Garry Shutler ngày 3 tháng 2 'lúc 16:59

tvanfosson chỉ giải thích nó dài dòng hơn một chút. "X không thể là hằng số, vì chứa Y là một lớp" chỉ hơi quá bối cảnh;) - Leonidas ngày 3 tháng 2 '09 lúc 17:01

string.Empty là thuộc tính tĩnh trả về một thể hiện của lớp String, cụ thể là chuỗi rỗng, không phải chính lớp chuỗi. - tvanfosson 3 tháng 2 '09 lúc 17:01

Trống là một thể hiện chỉ đọc (nó không phải là một thuộc tính) của lớp String. - senfo 3 tháng 2 '09 lúc 17:02

Chấn thương đầu. Tôi vẫn nghĩ rằng tôi đúng, nhưng bây giờ tôi ít chắc chắn hơn. Nghiên cứu cần thiết tối nay! - Garry Shutler 3 tháng 2 'lúc 17:07

Chuỗi rỗng là một thể hiện của lớp chuỗi. Trống là trường tĩnh (không phải là thuộc tính, tôi đứng chính xác) trên lớp Chuỗi. Về cơ bản sự khác biệt giữa một con trỏ và điều nó trỏ đến. Nếu nó không chỉ đọc, chúng ta có thể thay đổi trường hợp nào mà trường rỗng đề cập đến. - tvanfosson ngày 3 tháng 2 'lúc 17:07

Garry, bạn không cần phải làm bất kỳ nghiên cứu. Hãy suy nghĩ về nó. Chuỗi là một lớp. Trống là một thể hiện của một chuỗi. - senfo 3 tháng 2 '09 lúc 17:12

Có một thứ tôi không hoàn toàn hiểu được: làm thế nào trên trái đất, hàm tạo tĩnh của lớp String có thể tạo một thể hiện của lớp String? Không phải đó là một loại kịch bản "gà hay trứng" sao? - DrJokepu 3 tháng 2 '09 lúc 17:12 5

Câu trả lời này sẽ đúng cho gần như bất kỳ lớp nào khác ngoài System.String. .NET thực hiện rất nhiều hiệu năng đặc biệt cho các chuỗi và một trong số đó là bạn CÓ THỂ có các hằng chuỗi, chỉ cần thử nó. Trong trường hợp này, Jeff Yates có câu trả lời đúng. - Joel Mueller 3 tháng 2 '09 lúc 19:25

Như được mô tả trong §7,18, một biểu thức hằng là một biểu thức có thể được đánh giá đầy đủ tại thời gian biên dịch. Vì cách duy nhất để tạo giá trị không null của loại tham chiếu khác với chuỗi là áp dụng toán tử mới và vì toán tử mới không được phép trong biểu thức không đổi, nên giá trị duy nhất có thể cho các hằng số loại tham chiếu khác với chuỗi là null. Hai bình luận trước được lấy trực tiếp từ đặc tả ngôn ngữ C # và nhắc lại những gì Joel Mueller đã đề cập. - senfo 4 tháng 2 '09 lúc 15:05 5


Xin vui lòng, bỏ phiếu trả lời đúng. Nếu bạn Goto Định nghĩa, bạn sẽ thấy rằng nó nằm trong lớp Chuỗi và là một thể hiện của Chuỗi. Thực tế là nó hiển thị như chữ thường là ma thuật biên dịch.
Garry Shutler

Không phải tôi là người đánh giá thấp bạn nhưng trong .NET, chuỗi (không giống như trong Java) và Chuỗi hoàn toàn giống nhau. Và vâng, bạn có thể có các hằng chuỗi theo nghĩa đen trong .NET
Tamas Czinege

10
Câu trả lời này sẽ đúng cho gần như bất kỳ lớp nào khác ngoài System.String. .NET thực hiện rất nhiều hiệu năng đặc biệt cho các chuỗi và một trong số đó là bạn CÓ THỂ có các hằng chuỗi, chỉ cần thử nó. Trong trường hợp này, Jeff Yates có câu trả lời đúng.
Joel Mueller

7
Tôi gần như đã xóa câu trả lời này vì một câu trả lời hay hơn đã xuất hiện, nhưng cuộc thảo luận trong những bình luận này rất đáng để lưu giữ.
Garry Shutler

1
@Garry, bạn thật may mắn tôi đã đọc bình luận cuối cùng của bạn, nếu không tôi cũng sẽ downvote. Một chuỗi có một tính năng đặc biệt trong .NET, đó là một lớp ref, nó có thể là một hằng.
Shimmy Weitzhandler
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.