Từ C# specification, chapter 10.4 - Constants:
(10.4 trong đặc tả C# 3.0, 10.3 trong phiên bản trực tuyến với 2,0)
Một hằng là thành viên lớp đại diện cho một giá trị không đổi: một giá trị mà có thể được tính toán tại thời gian biên dịch.
Điều này về cơ bản nói rằng bạn chỉ có thể sử dụng các cụm từ chỉ bao gồm các chữ. Bất kỳ lời gọi nào đến bất kỳ phương thức nào, các hàm tạo (không thể được biểu diễn dưới dạng các chữ IL thuần túy) đều không thể được sử dụng, vì không có cách nào để trình biên dịch thực hiện điều đó và do đó tính toán kết quả, tại thời gian biên dịch. Ngoài ra, vì không có cách nào để gắn thẻ một phương thức là bất biến (ví dụ:có một ánh xạ một-một giữa đầu vào và đầu ra), cách duy nhất để trình biên dịch thực hiện điều này là phân tích IL để xem nó có phụ thuộc vào các thứ khác ngoài các tham số đầu vào, trường hợp đặc biệt xử lý một số loại (như IntPtr), hoặc không cho phép mọi cuộc gọi đến bất kỳ mã nào.
IntPtr, ví dụ, mặc dù là một loại giá trị, vẫn là một cấu trúc chứ không phải một trong các chữ cái dựng sẵn. Như vậy, bất kỳ biểu thức nào sử dụng IntPtr sẽ cần phải gọi mã trong cấu trúc IntPtr, và đây là điều không hợp pháp đối với một khai báo liên tục.
Ví dụ loại giá trị hằng số hợp pháp duy nhất mà tôi có thể nghĩ là một ví dụ được khởi tạo bằng số 0 bằng cách chỉ khai báo nó và điều đó hầu như không hữu ích.
Đối với cách trình biên dịch xử lý/sử dụng hằng số, nó sẽ sử dụng giá trị được tính thay cho tên không đổi trong mã.
Vì vậy, bạn có hiệu lực thi hành sau:
- Không tham chiếu đến tên liên tục ban đầu, lớp nó được khai báo trong, hoặc không gian tên, được biên soạn vào mã ở vị trí
- này Nếu bạn biên soạn lại các mã, nó sẽ có số ma thuật trong đó, đơn giản vì "tham chiếu" ban đầu cho hằng số, như đã đề cập ở trên, không có, chỉ giá trị của hằng số
- Trình biên dịch có thể sử dụng để tối ưu hóa hoặc thậm chí loại bỏ, mã không cần thiết. Ví dụ,
if (SomeClass.Version == 1)
, khi SomeClass.Version có giá trị là 1, trên thực tế sẽ loại bỏ câu lệnh if và giữ cho khối mã đang được thực thi. Nếu giá trị của hằng số không phải là 1, thì toàn bộ if-statement và khối của nó sẽ bị loại bỏ.
- Vì giá trị của hằng số được biên dịch vào mã và không tham chiếu đến hằng số, sử dụng hằng số từ các assembly khác sẽ không tự động cập nhật mã đã biên dịch theo bất kỳ cách nào nếu giá trị của hằng số thay đổi. không)
Nói cách khác, với các tình huống sau:
- hội A, chứa một hằng số có tên là "phiên bản", có giá trị là 1
- hội B, chứa một biểu thức phân tích số phiên bản của assembly A từ hằng số đó nd so sánh nó với 1, để đảm bảo nó có thể làm việc với các lắp ráp
- Có người sẽ thay đổi lắp ráp A, tăng giá trị của hằng số 2, và tái thiết A (nhưng không phải B)
Trong trường hợp này, lắp ráp B, ở dạng biên dịch của nó, sẽ vẫn so sánh giá trị từ 1 đến 1, bởi vì khi B được biên dịch, hằng số có giá trị 1.
Thực tế, nếu đó là cách sử dụng duy nhất của bất kỳ thứ gì từ lắp ráp A lắp ráp B, lắp ráp B sẽ được biên dịch mà không phụ thuộc vào lắp ráp A. Thực thi mã có chứa biểu thức đó trong lắp ráp B sẽ không tải lắp ráp A.
Hằng số do đó chỉ được sử dụng cho những thứ sẽ không bao giờ thay đổi. Nếu nó là một giá trị có thể hoặc sẽ thay đổi một thời gian trong tương lai, và bạn không thể đảm bảo rằng tất cả các hội đồng khác được xây dựng lại đồng thời, một trường chỉ đọc thích hợp hơn một hằng số.
Vì vậy, đây là ok:
- const công Int32 NumberOfDaysInAWeekInGregorianCalendar = 7;
- công khai const Int32 NumberOfHoursInADayOnEarth = 24;
trong khi đây không phải là:
- const công Int32 AgeOfProgrammer = 25;
- chuỗi công khai const NameOfLastProgrammerThatModifiedAssembly = "Joe Programmer";
Chỉnh sửa ngày 27 tháng 5 2016
OK, chỉ có một phiếu bầu tán thành, vì vậy tôi đọc lại câu trả lời của tôi ở đây và điều này thực sự là một chút sai.
Bây giờ, ý định đặc tả ngôn ngữ C# là mọi thứ tôi đã viết ở trên. Bạn không được phép sử dụng cái gì đó không thể được đại diện với một chữ như là một const
.
Nhưng bạn có thể? Vâng, vâng ....
Hãy xem loại decimal
.
public class Test
{
public const decimal Value = 10.123M;
}
Hãy nhìn vào những gì lớp này trông giống như thực sự khi nhìn với ildasm:
.field public static initonly valuetype [mscorlib]System.Decimal X
.custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(int8, uint8, uint32, uint32, uint32) = (01 00 01 00 00 00 00 00 00 00 00 00 64 00 00 00 00 00)
Hãy để tôi phá vỡ nó xuống cho bạn:
.field public static initonly
tương ứng với:
public static readonly
Đúng vậy, const decimal
thực sự là một readonly decimal
.
Thỏa thuận thực sự ở đây là trình biên dịch sẽ sử dụng DecimalConstantAttribute
để làm việc phép thuật của nó.
Bây giờ, đây là phép thuật duy nhất tôi biết với trình biên dịch C# nhưng tôi nghĩ nó đáng nói đến.
Rõ ràng là bạn không thể làm điều này nhưng * giả thuyết nói *, nói rằng chúng ta có một phương thức tĩnh kiểu giá trị trả về đã được đánh dấu bằng thuộc tính [Pure] và trình biên dịch thực sự thực thi nó (nó không phải hiện tại). Có thể các nhà thiết kế ngôn ngữ ít nhất * về mặt lý thuyết * cho phép một const được khởi tạo với phương thức thuần túy kiểu trả về tĩnh (với thực thi thuộc tính [Pure] thực tế) miễn là các đối số không là gì ngoài các chữ? Có vẻ như họ chỉ có thể chạy nó với các args đen, có được kết quả rõ ràng là sẽ không thay đổi và phụ trong giá trị. Tôi có nhìn cái gì không? –
'Trong trường hợp này, assembly B, ở dạng được biên dịch của nó, sẽ vẫn so sánh giá trị 1 đến 1, bởi vì khi B được biên dịch, hằng số có giá trị 1' - bạn vẫn có thể làm điều tương tự với' public const int AssemblyVersion = 1' trong bất kỳ phiên bản C# nào ngày hôm nay, vì vậy không có gì sai với * cấu trúc * mình –