2012-02-02 29 views
16

Có nhiều câu hỏi về chủ đề này, nhưng không có câu hỏi nào (ngoại trừ one but still a short one) đang xử lý kịch bản sau đây.Readonly tĩnh vs const - hội đồng khác nhau POV?

Từ C# 4 cuốn sách:

enter image description here

Marc cũng đã viết:

nếu bạn thay đổi giá trị của một const, bạn cần phải xây dựng lại tất cả các khách hàng

Câu hỏi:

1) Tại sao lại như vậy? Cả hai đều là static readonlyconst - static?

2) Trường hợp thực sự giá trị được lưu?

3) Làm cách nào để tạo một trường static readonly thực tế solve vấn đề này "đằng sau hiện trường"?

+2

Đó là bởi vì trình biên dịch sẽ "nội tuyến" giá trị của hằng số, thay vì tham chiếu một biến đến từ một assembly khác. – ken2k

+2

Không bao giờ biết về hành vi này của các const giữa các hội đồng. Câu hỏi hay –

Trả lời

21

không, const là một const, không tĩnh - nó là trường hợp đặc biệt, với các quy tắc khác nhau; nó là chỉ bộ tại thời gian biên dịch (không phải thời gian chạy), và nó được xử lý khác nhau

mấu chốt ở đây là những gì các phương tiện sau:

var foo = SomeType.StaticValue; 

vs

var bar = SomeType.ConstValue; 

trong trường hợp đầu tiên, nó đọc giá trị lúc chạy từ SomeType, tức là qua ldsfld; tuy nhiên, trong trường hợp thứ hai, được biên dịch thành giá trị, tức lànếu ConstValue sẽ xảy ra là 123, sau đó thứ hai là giống hệt tới:

var bar = 123; 

khi chạy, thực tế là nó đến từ SomeTypekhông tồn tại, như giá trị (123) được đánh giá bởi trình biên dịch và được lưu trữ. Do đó nó cần xây dựng lại để nhận các giá trị mới.

Thay đổi thành static readonly có nghĩa là "tải giá trị từ SomeType" được giữ nguyên.

Vì vậy, như sau:

static int Foo() 
{ 
    return Test.Foo; 
} 
static int Bar() 
{ 
    return Test.Bar; 
} 
... 
static class Test 
{ 
    public static readonly int Foo = 123; 
    public const int Bar = 456; 
} 

biên dịch như:

.method private hidebysig static int32 Bar() cil managed 
{ 
    .maxstack 8 
    L_0000: ldc.i4 0x1c8 
    L_0005: ret 
} 

.method private hidebysig static int32 Foo() cil managed 
{ 
    .maxstack 8 
    L_0000: ldsfld int32 ConsoleApplication2.Test::Foo 
    L_0005: ret 
} 

Lưu ý rằng trong Bar, các ldc đang tải một giá trị trực tiếp (0x1c8 == 456), với Test hoàn toàn Không còn.

Để hoàn chỉnh, const thực hiện với một lĩnh vực tĩnh, nhưng - nó là một đen lĩnh vực, có nghĩa là: đánh giá ở các trình biên dịch, không phải khi chạy.

.field public static literal int32 Bar = int32(0x1c8) 
.field public static initonly int32 Foo 
+0

cảm ơn câu trả lời xuất sắc, nhưng const không rõ ràng là tĩnh? –

+1

@Royi tốt, * có * trong rất nhiều vì nó được triển khai trong IL dưới dạng '.field ... static' và trong C# được truy cập dưới dạng' TypeName.ConstName' - nhưng điều quan trọng là ngữ nghĩa ** **; và về ý nghĩa của ngữ nghĩa, có sự khác biệt lớn giữa việc truy cập một thành viên tĩnh thông thường (trường/prop) và truy cập vào một thành viên const. –

4

Bạn đã trả lời câu hỏi của mình bằng hình ảnh bạn đã liên kết. Các trường const sẽ được biên dịch ("inlined") vào trong assembly - giống như một tìm kiếm đơn giản và thay thế. static readonly là trường thông thường không được phép thay đổi và chỉ tồn tại một lần trong bộ nhớ, nhưng vẫn được tham chiếu theo vị trí bộ nhớ.

Trong Khuôn khổ .NET, hằng số không được chỉ định vùng bộ nhớ, nhưng thay vào đó, được coi là giá trị. Do đó, bạn không bao giờ có thể gán hằng số , nhưng việc tải hằng số vào bộ nhớ hiệu quả hơn vì nó có thể được tiêm trực tiếp vào luồng lệnh. Điều này loại bỏ mọi bộ nhớ truy cập bên ngoài bộ nhớ, cải thiện địa phương tham chiếu. http://www.dotnetperls.com/optimization

6

1) const chỉ được giải quyết trong thời gian biên dịch với giá trị mà bạn đã cung cấp. Trong khi static readonly là biến tĩnh.

2) static giá trị thường được lưu trữ trên một khu vực đặc biệt trên heap được gọi là High Frequency Heap. Như tôi đã nói trước đây consts được thay thế tại thời gian biên dịch.

3) làm cho nó static readonly sẽ giải quyết vấn đề vì bạn sẽ đọc giá trị biến trong thời gian chạy, không phải là giá trị được cung cấp tại thời gian biên dịch.

24

nếu bạn thay đổi giá trị của một const, bạn cần phải xây dựng lại tất cả các khách hàng

Đó không phải là giải pháp đúng. Nếu bạn thay đổi giá trị của một const thì nó không phải là hằng số. Hằng số theo định nghĩa những thứ không bao giờ thay đổi giá trị. Ý tưởng rằng bạn sẽ thay đổi giá trị của một hằng số có nghĩa là bạn đang làm điều gì đó một cách hợp lý không thể, và do đó tất nhiên mọi thứ sẽ bị hỏng; bạn đang làm một cái gì đó mà bạn nói bạn sẽ không làm. Nếu bạn đi xung quanh nói dối với trình biên dịch, và nó đau khi bạn làm điều đó, sau đó ngừng nằm vào trình biên dịch.

Giá vàng không phải là hằng số. Tên ngân hàng của bạn không phải là một hằng số. Số phiên bản của chương trình của bạn không phải là một hằng số. Những thứ này thay đổi, do đó, không làm cho chúng hằng số. Hằng số là những thứ như pi, hoặc số lượng proton trong một nguyên tử vàng.

Biến là những thứ có thể thay đổi - đó là lý do tại sao chúng được gọi là "biến". Hằng số là những thứ ở lại ... liên tục. Nếu nó có thể thay đổi, hãy biến nó thành một biến. Nếu nó là hằng số, hãy biến nó thành hằng số. Nó đơn giản như vậy.

tại sao vậy? cả chỉ đọc và const tĩnh đều tĩnh là

Chắc chắn. Nó phải làm gì với nó? "tĩnh" trong C# có nghĩa là "phần tử được đặt tên được liên kết với loại, thay vì với bất kỳ trường hợp cụ thể nào của loại". ("Tĩnh" do đó là một sự lựa chọn kém của các điều khoản, VB làm tốt hơn với "chia sẻ".)

Cho dù tên được liên kết với loại hoặc một thể hiện không liên quan đến câu hỏi liệu tên đề cập đến một hằng số hoặc biến.

nơi thực sự các giá trị đang được lưu trong cả hai chỉ đọc tĩnh vsconst?

Khi bạn sử dụng giá trị không đổi, giá trị được "nướng" ở bất cứ nơi nào được sử dụng. Đó là an toàn bởi vì nó sẽ không bao giờ thay đổi. Nó sẽ không bao giờ thay đổi bởi vì nó là hằng số và đó là ý nghĩa của "hằng số".

Khi bạn sử dụng biến, giá trị của biến được tra cứu theo thời gian chạy mỗi lần. "chỉ đọc" chỉ có nghĩa là "biến này chỉ có thể được thay đổi trong hàm tạo lớp hoặc trình khởi tạo trường". Nó vẫn là một biến. (*)

cách tạo trường tĩnh chỉ đọc - thực sự giải quyết vấn đề này đằng sau hiện trường?

Bạn chưa nêu vấn đề là gì, vì vậy tôi không biết bạn đang cố giải quyết vấn đề gì.


(*) lĩnh vực chỉ đọc được coi là giá trị không đổi bên ngoài các nhà xây dựng, do đó một lĩnh vực readonly của kiểu giá trị có thể thay đổi không thể được biến đổi, và do đó bạn không thể lấy một ref đến một readonly và sau đó thay đổi tham chiếu.

+1

Bây giờ tôi hiểu ý nghĩa của câu này !: Nếu bạn nói dối với trình biên dịch, nó sẽ trả thù - Henry Spencer – kokabi

+0

Bài viết của bạn rất hay. Tại sao không viết một cuốn sách tuyệt vời về C#. đó là giấc mơ của tôi! – kokabi

+1

@ programmer1: Cảm ơn! Tôi đã giúp Viết ra bằng văn bản vài ấn bản cuối cùng của Essential C#, nhưng phần lớn văn bản là của anh ấy. Tôi đã nghĩ về việc viết một cuốn sách C# của riêng tôi, nhưng nó là rất nhiều công việc. Ngoài ra, tôi viết một blog về thiết kế của C#. –

0

Tôi đoán chúng ta có thể nghĩ về hằng số dưới dạng giá trị mã hóa trong mã của chúng tôi, nhưng với các dịch vụ bảo trì và khả năng sử dụng tốt hơn.

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