Sự khác biệt giữa const
và readonly
trong C # là gì?
Khi nào bạn sẽ sử dụng cái này hơn cái kia?
Sự khác biệt giữa const
và readonly
trong C # là gì?
Khi nào bạn sẽ sử dụng cái này hơn cái kia?
Câu trả lời:
Ngoài sự khác biệt rõ ràng của
const
VS readonly
có thể được tính toán động nhưng cần được chỉ định trước khi hàm tạo thoát ra .. sau đó nó bị đóng băng.static
. Bạn sử dụng một ClassName.ConstantName
ký hiệu để truy cập chúng.Có một sự khác biệt tinh tế. Hãy xem xét một lớp được định nghĩa trong AssemblyA
.
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly int I_RO_VALUE;
public Const_V_Readonly()
{
I_RO_VALUE = 3;
}
}
AssemblyB
tài liệu tham khảo AssemblyA
và sử dụng các giá trị này trong mã. Khi điều này được biên dịch,
const
giá trị, nó giống như một tìm kiếm thay thế, giá trị 2 được 'nướng vào' AssemblyB
IL. Điều này có nghĩa là nếu ngày mai tôi sẽ cập nhật I_CONST_VALUE
lên 20 trong tương lai. AssemblyB
vẫn sẽ có 2 cho đến khi tôi biên dịch lại nó .readonly
giá trị, nó giống như một ref
vị trí bộ nhớ. Giá trị không được đưa vào AssemblyB
IL. Điều này có nghĩa là nếu vị trí bộ nhớ được cập nhật, AssemblyB
sẽ nhận được giá trị mới mà không cần biên dịch lại. Vì vậy, nếu I_RO_VALUE
được cập nhật lên 30, bạn chỉ cần xây dựng AssemblyA
. Tất cả các khách hàng không cần phải biên dịch lại.Vì vậy, nếu bạn tự tin rằng giá trị của hằng số sẽ không thay đổi, hãy sử dụng a const
.
public const int CM_IN_A_METER = 100;
Nhưng nếu bạn có một hằng số có thể thay đổi (ví dụ độ chính xác) .. hoặc khi nghi ngờ, hãy sử dụng a readonly
.
public readonly float PI = 3.14;
Cập nhật: Aku cần nhận được một đề cập vì anh ấy đã chỉ ra điều này trước tiên. Ngoài ra tôi cần phải cắm vào nơi tôi đã học được điều này .. C # hiệu quả - Bill Wagner
static
điểm có vẻ là điểm quan trọng nhất và hữu ích -consts are implicitly static
readonly
các biến có thể được thay đổi bên ngoài hàm tạo (sự phản chiếu). Nó chỉ là trình biên dịch cố gắng cản trở bạn sửa đổi var bên ngoài hàm tạo.
readonly
không được phép thay đổi sau khi hàm tạo hoàn thành, thậm chí thông qua phản xạ. Thời gian chạy xảy ra để không thực thi điều này. Thời gian chạy cũng xảy ra không để thực thi mà bạn không thay đổi string.Empty
đến "Hello, world!"
, nhưng tôi vẫn sẽ không cho rằng điều này làm cho string.Empty
sửa đổi, hoặc mã mà không nên cho rằng string.Empty
sẽ luôn luôn là một chuỗi zero-length.
Có một gotcha với consts! Nếu bạn tham chiếu một hằng số từ một cụm khác, giá trị của nó sẽ được biên dịch ngay vào cụm gọi. Theo cách đó, khi bạn cập nhật hằng số trong cụm được tham chiếu, nó sẽ không thay đổi trong cụm gọi!
Chỉ cần thêm, ReadOnly cho các loại tham chiếu chỉ làm cho tham chiếu chỉ đọc không phải là các giá trị. Ví dụ:
public class Const_V_Readonly
{
public const int I_CONST_VALUE = 2;
public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};
public UpdateReadonly()
{
I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
I_RO_VALUE = new char[]{'V'}; //will cause compiler error
}
}
string
mà bạn có thể sử dụng như một hằng số không?
const
các kiểu tham chiếu khác với chuỗi, nhưng hằng số chỉ có thể có giá trị null
.
Điều này giải thích nó . Tóm tắt: const phải được khởi tạo tại thời điểm khai báo, chỉ có thể được khởi tạo trên hàm tạo (và do đó có giá trị khác nhau tùy thuộc vào hàm tạo được sử dụng).
EDIT: Xem gotcha của Gishu ở trên để biết sự khác biệt tinh tế
Có một gotcha nhỏ với chỉ đọc. Một trường chỉ đọc có thể được đặt nhiều lần trong (các) hàm tạo. Ngay cả khi giá trị được đặt trong hai hàm tạo chuỗi khác nhau, nó vẫn được phép.
public class Sample {
private readonly string ro;
public Sample() {
ro = "set";
}
public Sample(string value) : this() {
ro = value; // this works even though it was set in the no-arg ctor
}
}
Một thành viên không đổi được định nghĩa tại thời gian biên dịch và không thể thay đổi khi chạy. Các hằng số được khai báo là một trường, sử dụng const
từ khóa và phải được khởi tạo khi chúng được khai báo.
public class MyClass
{
public const double PI1 = 3.14159;
}
Một readonly
thành viên giống như một hằng số ở chỗ nó đại diện cho một giá trị không thay đổi. Sự khác biệt là một readonly
thành viên có thể được khởi tạo trong thời gian chạy, trong một hàm tạo, cũng như có thể được khởi tạo khi chúng được khai báo.
public class MyClass1
{
public readonly double PI2 = 3.14159;
//or
public readonly double PI3;
public MyClass2()
{
PI3 = 3.14159;
}
}
hăng sô
static
(chúng hoàn toàn tĩnh)chỉ đọc
static const int i = 0;
const
khai báo không thể được thực hiện bên trong các phương thức?
Một const là hằng số thời gian biên dịch trong khi chỉ đọc cho phép một giá trị được tính tại thời gian chạy và được đặt trong hàm tạo hoặc trình khởi tạo trường. Vì vậy, một 'const' luôn luôn không đổi nhưng 'chỉ đọc' chỉ đọc khi được gán.
Eric Lippert của nhóm C # có thêm thông tin về các loại bất biến khác nhau
Đây là một liên kết khác chứng minh làm thế nào const không phải là phiên bản an toàn hoặc có liên quan cho các loại tham chiếu.
Tóm tắt :
Chỉ đọc : Giá trị có thể được thay đổi thông qua Ctor khi chạy. Nhưng không thông qua chức năng thành viên
Hằng : Bằng cách bất chấp tĩnh. Giá trị không thể thay đổi từ bất cứ đâu (Ctor, Function, runtime v.v.
Tuy nhiên, một giá trị gotcha khác: giá trị chỉ đọc có thể được thay đổi bằng mã "lệch lạc" thông qua sự phản chiếu.
var fi = this.GetType()
.BaseType
.GetField("_someField",
BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);
Tôi có thể thay đổi trường kế thừa chỉ đọc riêng tư trong C # bằng phản chiếu không?
Tôi tin rằng một const
giá trị là giống nhau cho tất cả các đối tượng (và phải được khởi tạo bằng biểu thức bằng chữ), trong khi readonly
có thể khác nhau cho mỗi lần khởi tạo ...
Một trong các thành viên trong văn phòng của chúng tôi đã cung cấp hướng dẫn sau đây về thời điểm sử dụng const, tĩnh và chỉ đọc:
Một lưu ý cuối cùng: một trường const là tĩnh, nhưng nghịch đảo là không đúng.
Cả hai đều là hằng số, nhưng một const cũng có sẵn tại thời gian biên dịch. Điều này có nghĩa là một khía cạnh của sự khác biệt là bạn có thể sử dụng các biến const làm đầu vào cho các hàm tạo thuộc tính, nhưng không phải là các biến chỉ đọc.
Thí dụ:
public static class Text {
public const string ConstDescription = "This can be used.";
public readonly static string ReadonlyDescription = "Cannot be used.";
}
public class Foo
{
[Description(Text.ConstDescription)]
public int BarThatBuilds {
{ get; set; }
}
[Description(Text.ReadOnlyDescription)]
public int BarThatDoesNotBuild {
{ get; set; }
}
}
khi nào sử dụng const
hoặcreadonly
const
readonly
App.config
, nhưng một khi nó khởi chạy thì không thể thay đổiCác biến được đánh dấu const ít hơn một chút so với các macro #define được gõ mạnh, tại thời điểm biên dịch các tham chiếu biến const được thay thế bằng các giá trị bằng chữ. Kết quả là chỉ có các loại giá trị nguyên thủy tích hợp nhất định có thể được sử dụng theo cách này. Các biến được đánh dấu chỉ đọc có thể được đặt, trong một hàm tạo, tại thời gian chạy và tính năng chỉ đọc của chúng cũng được thực thi trong thời gian chạy. Có một số chi phí hiệu suất nhỏ liên quan đến điều này nhưng điều đó có nghĩa là bạn có thể sử dụng chỉ đọc với bất kỳ loại nào (ngay cả các loại tham chiếu).
Ngoài ra, các biến const vốn là tĩnh, trong khi các biến chỉ đọc có thể là trường hợp cụ thể nếu muốn.
Một Gotcha khác .
Vì const thực sự chỉ hoạt động với các kiểu dữ liệu cơ bản, nên nếu bạn muốn làm việc với một lớp, bạn có thể cảm thấy "bị ép buộc" sử dụng ReadOnly. Tuy nhiên, hãy cẩn thận với cái bẫy! ReadOnly có nghĩa là bạn không thể thay thế đối tượng bằng một đối tượng khác (bạn không thể làm cho nó tham chiếu đến một đối tượng khác). Nhưng bất kỳ quá trình nào có tham chiếu đến đối tượng đều được tự do sửa đổi các giá trị bên trong đối tượng!
Vì vậy, đừng nhầm lẫn khi nghĩ rằng ReadOnly ngụ ý người dùng không thể thay đổi mọi thứ. Không có cú pháp đơn giản nào trong C # để ngăn việc khởi tạo một lớp thay đổi giá trị bên trong của nó (theo như tôi biết).
Có sự khác biệt đáng chú ý giữa các trường const và chỉ đọc trong C # .Net
const theo mặc định là tĩnh và cần được khởi tạo với giá trị không đổi, không thể sửa đổi sau này. Thay đổi giá trị cũng không được phép trong các nhà xây dựng. Nó không thể được sử dụng với tất cả các kiểu dữ liệu. Ví dụ: DateTime. Nó không thể được sử dụng với kiểu dữ liệu DateTime.
public const DateTime dt = DateTime.Today; //throws compilation error
public const string Name = string.Empty; //throws compilation error
public readonly string Name = string.Empty; //No error, legal
chỉ đọc có thể được khai báo là tĩnh, nhưng không cần thiết. Không cần phải khởi tạo tại thời điểm khai báo. Giá trị của nó có thể được gán hoặc thay đổi bằng cách sử dụng hàm tạo. Vì vậy, nó mang lại lợi thế khi được sử dụng làm thành viên lớp thể hiện. Hai khởi tạo khác nhau có thể có giá trị khác nhau của trường chỉ đọc. Dành cho người cũ
class A
{
public readonly int Id;
public A(int i)
{
Id = i;
}
}
Sau đó, trường chỉ đọc có thể được khởi tạo với các giá trị cụ thể ngay lập tức, như sau:
A objOne = new A(5);
A objTwo = new A(10);
Ở đây, ví dụ objOne sẽ có giá trị của trường chỉ đọc là 5 và objTwo có 10. Không thể sử dụng const.
Một hằng số sẽ được biên dịch vào người tiêu dùng dưới dạng giá trị bằng chữ trong khi chuỗi tĩnh sẽ đóng vai trò tham chiếu đến giá trị được xác định.
Như một bài tập, hãy thử tạo thư viện bên ngoài và sử dụng nó trong ứng dụng bảng điều khiển, sau đó thay đổi các giá trị trong thư viện và biên dịch lại (không biên dịch lại chương trình tiêu dùng), thả DLL vào thư mục và chạy EXE theo cách thủ công, bạn nên tìm chuỗi không đổi không thay đổi.
Không thay đổi
Chúng ta cần cung cấp giá trị cho trường const khi nó được xác định. Trình biên dịch sau đó lưu giá trị của hằng trong siêu dữ liệu của tổ hợp. Điều này có nghĩa là một hằng số chỉ có thể được định nghĩa cho kiểu nguyên thủy như boolean, char, byte, v.v. Các hằng số luôn được coi là thành viên tĩnh, không phải thành viên thể hiện.
Chỉ đọc
Các trường chỉ đọc chỉ có thể được giải quyết trong thời gian chạy. Điều đó có nghĩa là chúng ta có thể định nghĩa một giá trị cho một giá trị bằng cách sử dụng hàm tạo cho kiểu mà trường được khai báo. Việc xác minh được thực hiện bởi trình biên dịch rằng các trường chỉ đọc không được ghi bởi bất kỳ phương thức nào khác ngoài hàm tạo.
Thông tin thêm về cả hai được giải thích ở đây trong bài viết này
Const và readonly tương tự nhau, nhưng chúng không hoàn toàn giống nhau. Trường const là hằng số thời gian biên dịch, nghĩa là giá trị đó có thể được tính tại thời gian biên dịch. Trường chỉ đọc cho phép các kịch bản bổ sung trong đó một số mã phải được chạy trong khi xây dựng loại. Sau khi xây dựng, một trường chỉ đọc có thể được thay đổi.
Chẳng hạn, các thành viên const có thể được sử dụng để xác định các thành viên như:
struct Test
{
public const double Pi = 3.14;
public const int Zero = 0;
}
vì các giá trị như 3.14 và 0 là các hằng số thời gian biên dịch. Tuy nhiên, hãy xem xét trường hợp bạn xác định một loại và muốn cung cấp một số phiên bản pre-fab của loại đó. Ví dụ, bạn có thể muốn xác định lớp Màu và cung cấp "hằng số" cho các màu phổ biến như Đen, Trắng, v.v. Không thể làm điều này với các thành viên const, vì phía bên tay phải không phải là hằng số thời gian biên dịch. Người ta có thể làm điều này với các thành viên tĩnh thông thường:
public class Color
{
public static Color Black = new Color(0, 0, 0);
public static Color White = new Color(255, 255, 255);
public static Color Red = new Color(255, 0, 0);
public static Color Green = new Color(0, 255, 0);
public static Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) {
red = r;
green = g;
blue = b;
}
}
nhưng sau đó, không có gì để giữ cho khách hàng của Color không bị làm phiền với nó, có lẽ bằng cách hoán đổi các giá trị Đen và Trắng. Không cần phải nói, điều này sẽ gây ra sự bối rối cho các khách hàng khác của lớp Màu. Tính năng "chỉ đọc" giải quyết tình huống này. Bằng cách đơn giản là giới thiệu từ khóa chỉ đọc trong các khai báo, chúng tôi duy trì việc khởi tạo linh hoạt trong khi ngăn chặn mã máy khách khỏi bị lừa đảo.
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) {
red = r;
green = g;
blue = b;
}
}
Thật thú vị khi lưu ý rằng các thành viên const luôn tĩnh, trong khi một thành viên chỉ đọc có thể là tĩnh hoặc không, giống như một trường thông thường.
Có thể sử dụng một từ khóa duy nhất cho hai mục đích này, nhưng điều này dẫn đến các vấn đề về phiên bản hoặc vấn đề về hiệu suất. Giả sử trong một khoảnh khắc chúng tôi đã sử dụng một từ khóa duy nhất cho (const) này và một nhà phát triển đã viết:
public class A
{
public static const C = 0;
}
và một nhà phát triển khác đã viết mã dựa trên A:
public class B
{
static void Main() {
Console.WriteLine(A.C);
}
}
Bây giờ, mã được tạo có thể dựa vào thực tế rằng AC là hằng số thời gian biên dịch không? Tức là, việc sử dụng AC có thể được thay thế bằng giá trị 0 không? Nếu bạn nói "có" với điều này, thì điều đó có nghĩa là nhà phát triển của A không thể thay đổi cách khởi tạo AC - điều này ràng buộc tay của nhà phát triển A mà không được phép. Nếu bạn nói "không" với câu hỏi này thì việc tối ưu hóa quan trọng sẽ bị bỏ qua. Có lẽ tác giả của A tích cực rằng AC sẽ luôn bằng không. Việc sử dụng cả const và readonly cho phép nhà phát triển của A chỉ định ý định. Điều này làm cho hành vi phiên bản tốt hơn và hiệu suất tốt hơn.
Sự khác biệt là giá trị của trường chỉ đọc tĩnh được đặt tại thời gian chạy, do đó, nó có thể có giá trị khác nhau cho các lần thực hiện khác nhau của chương trình. Tuy nhiên, giá trị của trường const được đặt thành hằng số thời gian biên dịch.
Ghi nhớ: Đối với các loại tham chiếu, trong cả hai trường hợp (tĩnh và thể hiện), công cụ sửa đổi chỉ đọc chỉ ngăn bạn gán một tham chiếu mới cho trường. Nó đặc biệt không làm cho đối tượng được chỉ ra bởi tham chiếu.
Để biết chi tiết, vui lòng tham khảo C # Câu hỏi thường gặp về chủ đề này: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx
Các biến không đổi được khai báo và khởi tạo tại thời điểm biên dịch. Giá trị không thể thay đổi sau khi phường. Các biến chỉ đọc sẽ chỉ được khởi tạo từ hàm tạo tĩnh của lớp. Chỉ đọc chỉ được sử dụng khi chúng ta muốn gán giá trị trong thời gian chạy.
Const : Giá trị không đổi tuyệt đối trong suốt thời gian sử dụng.
Chỉ đọc : Nó có thể được thay đổi trong thời gian chạy.
Một điều để thêm vào những gì mọi người đã nói ở trên. Nếu bạn có một hội đồng chứa giá trị chỉ đọc (ví dụ: chỉ đọc MaxFooCount = 4;), bạn có thể thay đổi giá trị mà các hội đồng gọi thấy bằng cách vận chuyển một phiên bản mới của hội đồng đó với một giá trị khác (ví dụ: chỉ đọc MaxFooCount = 5;)
Nhưng với một hằng số, nó sẽ được gấp lại thành mã của người gọi khi người gọi được biên dịch.
Nếu bạn đã đạt đến mức độ thành thạo C # này, bạn đã sẵn sàng cho cuốn sách của Bill Wagner, C # hiệu quả: 50 cách cụ thể để cải thiện C # của bạn Trả lời chi tiết câu hỏi này, và 49 điều khác).