Sự khác biệt quan trọng nhất giữa a class
và a struct
là những gì xảy ra trong tình huống sau:
Điều thứ 1 = điều mới ();
điều1.somePropertyOrField = 5;
Điều thứ 2 = điều1;
điều2.somePropertyOrField = 9;
Điều gì sẽ có hiệu lực của tuyên bố cuối cùng trên thing1.somePropertyOrField
? Nếu Thing
một cấu trúc, và somePropertyOrField
là một trường công khai lộ ra, các đối tượng thing1
và thing2
sẽ được "tách rời" khỏi nhau, vì vậy câu lệnh sau sẽ không ảnh hưởng thing1
. Nếu Thing
là một lớp, sau đó thing1
và thing2
sẽ được gắn với nhau, và vì vậy câu lệnh sau sẽ viết thing1.somePropertyOrField
. Người ta nên sử dụng một cấu trúc trong trường hợp ngữ nghĩa trước sẽ có ý nghĩa hơn và nên sử dụng một lớp trong trường hợp ngữ nghĩa sau sẽ có ý nghĩa hơn.
Lưu ý rằng trong khi một số người khuyên rằng mong muốn tạo ra thứ gì đó có thể thay đổi là một lý lẽ ủng hộ nó là lớp, tôi sẽ đề xuất điều ngược lại là đúng: nếu thứ gì đó tồn tại với mục đích giữ một số dữ liệu sẽ có thể thay đổi được, và nếu không rõ liệu các thể hiện có được gắn vào bất cứ thứ gì hay không, thì vật đó phải là một cấu trúc (có thể có các trường được phơi bày) để làm rõ rằng các thể hiện đó không được gắn với bất kỳ thứ gì khác.
Ví dụ, hãy xem xét các tuyên bố:
Person somePerson = myP People.GetPerson ("123-45-6789");
somePerson.Name = "Mary Johnson"; // Đã là "Mary Smith"
Tuyên bố thứ hai sẽ thay đổi thông tin được lưu trữ trong myPeople
? Nếu Person
là một cấu trúc trường tiếp xúc, nó sẽ không, và thực tế là nó sẽ không phải là một hậu quả rõ ràng của việc nó là một cấu trúc trường tiếp xúc ; Nếu Person
là một cấu trúc và một người muốn cập nhật myPeople
, rõ ràng người ta sẽ phải làm một cái gì đó như thế nào myPeople.UpdatePerson("123-45-6789", somePerson)
. Person
Tuy nhiên, nếu là một lớp, có thể khó hơn nhiều để xác định liệu đoạn mã trên sẽ không bao giờ cập nhật nội dung của MyPeople
, luôn cập nhật nó hay đôi khi cập nhật nó.
Liên quan đến khái niệm rằng các cấu trúc nên là "bất biến", tôi không đồng ý nói chung. Có các trường hợp sử dụng hợp lệ cho các cấu trúc "bất biến" (trong đó các bất biến được thi hành trong một hàm tạo) nhưng yêu cầu toàn bộ cấu trúc phải được viết lại bất cứ khi nào bất kỳ phần nào của nó thay đổi là lúng túng, lãng phí và dễ gây ra lỗi hơn là chỉ đơn giản là phơi bày lĩnh vực trực tiếp. Ví dụ, hãy xem xét một PhoneNumber
cấu trúc có các trường, bao gồm các trường khác AreaCode
và Exchange
, giả sử một trường có một List<PhoneNumber>
. Hiệu quả của những điều sau đây phải khá rõ ràng:
for (int i = 0; i <myList.Count; i ++)
{
PhoneNumber theNumber = myList [i];
if (theNumber.AreaCode == "312")
{
chuỗi newExchange = "";
if (new312to708Exchanges.TryGetValue (theNumber.Exchange), ra newExchange)
{
theNumber.AreaCode = "708";
theNumber.Exchange = newExchange;
myList [i] = theNumber;
}
}
}
Lưu ý rằng không có gì trong đoạn mã trên biết hoặc quan tâm đến bất kỳ lĩnh vực nào PhoneNumber
khác ngoài AreaCode
và Exchange
. Nếu PhoneNumber
là một cấu trúc được gọi là "bất biến", thì nó sẽ cần một withXX
phương thức cho mỗi trường, nó sẽ trả về một thể hiện cấu trúc mới giữ giá trị truyền vào trong trường được chỉ định, hoặc nếu không thì sẽ cần thiết cho mã như trên để biết về mọi lĩnh vực trong cấu trúc. Không chính xác hấp dẫn.
BTW, có ít nhất hai trường hợp trong đó các cấu trúc có thể giữ hợp lý các tham chiếu đến các loại có thể thay đổi.
- Các ngữ nghĩa của cấu trúc chỉ ra rằng nó lưu trữ danh tính của đối tượng được đề cập, chứ không phải là một phím tắt để giữ các thuộc tính của đối tượng. Ví dụ, một `KeyValuePair` sẽ giữ danh tính của một số nút nhất định, nhưng sẽ không được dự kiến sẽ giữ thông tin liên tục về các vị trí của các nút đó, trạng thái tô sáng, v.v.
- Cấu trúc biết rằng nó giữ tham chiếu duy nhất cho đối tượng đó, không ai khác sẽ nhận được một tham chiếu và bất kỳ đột biến nào sẽ được thực hiện cho đối tượng đó sẽ được thực hiện trước khi tham chiếu đến nó được lưu trữ ở bất cứ đâu.
Trong kịch bản cũ, IDENTITY của đối tượng sẽ là bất biến; trong phần hai, lớp của đối tượng lồng nhau có thể không thực thi tính bất biến, nhưng cấu trúc giữ tham chiếu sẽ.