2010-12-10 31 views
13

Hôm nay tôi có một chút ngạc nhiên khi tôi thay đổi giá trị của hằng số hiển thị công khai trong một lớp tĩnh và sau đó thay thế một bản sao cũ của phiên bản bằng phiên bản mới được biên dịch. Điều ngạc nhiên là chương trình hiện tại tham chiếu đến hội đồng không nhận giá trị mới của hằng số. Đó là, tôi đã không biên dịch lại file thực thi mà chỉ thay thế một assembly.Trong .NET, tại sao các hằng số được đánh giá tại thời gian biên dịch chứ không phải thời gian JIT?

Một mô tả đầy đủ các thử nghiệm của tôi là tại How constant is a constant?

tôi sẽ thừa nhận là rất ngạc nhiên bởi hành vi này. Tôi hiểu điều gì đang xảy ra nhưng tôi không hiểu lý do tại sao. Có một lý do kỹ thuật cụ thể tại sao hằng số không thể được chọn vào thời gian JIT thay vì biên dịch thời gian? Có trường hợp nào làm điều đó sẽ phá vỡ mọi thứ?

+0

Đây là một hành vi được thảo luận trong quá nhiều sách, bài đăng trên blog, vì vậy nó không phải là đáng ngạc nhiên trên thực tế :) –

+0

@Lex: Nhưng kỳ lạ, tôi 'd không bao giờ chạy qua một cuộc thảo luận về nó trước đây. Tôi vẫn tự hỏi * tại sao *. –

+1

Tôi vẫn không nhận được những lợi thế của việc nướng nó vào lắp ráp bằng cách sử dụng là. – CodesInChaos

Trả lời

30

Hằng số được coi là hằng số. Đối với mọi lúc. Hằng số là những thứ như giá trị của pi, hoặc số lượng proton trong một nguyên tử chì.

Nếu hằng số của bạn thay đổi, nó không thực sự là hằng số; sử dụng một trường chỉ đọc thay thế.

Cũng xem Hướng dẫn thiết kế Framework, mà nhà nước:

Sử dụng các lĩnh vực liên tục cho các hằng số đó sẽ không bao giờ thay đổi. Trình biên dịch ghi các giá trị của các trường const trực tiếp vào mã gọi. Do đó các giá trị const không bao giờ có thể thay đổi mà không có nguy cơ phá vỡ tính tương thích.

Về cơ bản, thay đổi hằng số mà không biên dịch lại mọi thứ phụ thuộc vào nó bị hỏng như thay đổi chữ ký của phương pháp mà không biên dịch lại mọi thứ phụ thuộc vào nó. Trình biên dịch "bakes in" tất cả các loại giả định về thông tin về siêu dữ liệu từ các assembly được tham chiếu khi nó biên dịch một assembly phụ thuộc. Nếu bạn thực hiện bất kỳ thay đổi nào, bạn không thể mong đợi mọi thứ đơn giản tiếp tục hoạt động.

+0

Trình biên dịch JIT có đánh giá các trường chỉ đọc và sau đó coi chúng là hằng số khi biên dịch thành mã gốc không? Tức là, có sự khác biệt hiệu suất giữa việc sử dụng hằng số và sử dụng một trường chỉ đọc không? –

+5

@Jim: Tôi không biết.Trước hết, có một nửa tá hoặc nhiều hơn JIT trình biên dịch và tôi là một chuyên gia về không ai trong số họ. Thứ hai, các trình biên dịch JIT thường thay đổi hành vi của chúng dựa trên những thứ xảy ra trong thời gian chạy, giống như một trình gỡ lỗi có được đính kèm hay không. Thứ ba, nếu bạn lo ngại về hiệu suất, hãy viết mã theo cả hai cách, chạy nó và xem liệu bạn có thể đo lường sự khác biệt hay không. Nếu sự khác biệt quá nhỏ để đo thì có lẽ đó không phải là sự khác biệt mà bạn nên lo lắng ngay từ đầu. –

+7

Tôi nghe PI bây giờ là chính xác 3. – ChaosPandion

1

Ngoài ra còn có cách thứ ba để khai báo "hằng số": thuộc tính tĩnh công cộng.

public static string ConstString {get{return "First test";}} 

Điều này có ngữ nghĩa phiên bản của trường chỉ đọc, nhưng nếu jitter inline getter nó trở thành hằng số jit-time. Và không giống như const, nó có thể được sử dụng trên các loại do người dùng xác định.

Tôi nghĩ nên sử dụng các thuộc tính tĩnh cho các kiểu giá trị và chuỗi, nhưng không phải cho các lớp do người dùng định nghĩa vì bạn không muốn cấp phát một cá thể mới trên mỗi truy cập thuộc tính.

tôi đã sử dụng này trong loại FixedPoint của tôi như thế này:

public struct FixedPoint 
{ 
    private int raw; 
    private const fracDigits=16; 

    private FixedPoint(int raw) 
    { 
    this.raw=raw; 
    } 

    public static FixedPoint Zero{get{return new FixedPoint();}} 
    public static FixedPoint One{get{return new FixedPoint(1<<fracDigits);}} 
    public static FixedPoint MaxValue{get{return new FixedPoint(int.MaxValue);}} 
} 
Các vấn đề liên quan