Đại biểu C # là bất biến - nhưng tại sao điều đó lại quan trọng?


8

Đây là một câu hỏi tiếp theo cho câu hỏi khác này.

Lý lịch

Làm việc từ Hướng dẫn dành cho đại biểu MSDN (C #) , tôi thấy như sau:

Lưu ý rằng một khi một đại biểu được tạo, phương thức được liên kết với không bao giờ thay đổi - các đối tượng ủy nhiệm là bất biến.

Và sau đó, trong mẫu mã, tôi thấy điều này (Trải ra một chút thông qua mã):

public delegate void ProcessBookDelegate(Book book);

bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(PrintTitle));
bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(totaller.AddBookToTotal));

Câu hỏi

Bây giờ rõ ràng, cách viết mã ở đây một đại biểu mới được tạo cho mỗi quy trình. Tôi đoán sự bất biến có liên quan nếu bạn cố gắng làm những việc như

ProcessBookDelegate thisIsATest = new ProcessBookDelegate(PrintTitle);
ProcessBookDelegate thisIsATest = new ProcessBookDelegate(totaller.AddBookToTotal);

Mà nên ... vẫn biên dịch khi thisIsATestbất biến? Vậy Microsoft đã giải quyết vấn đề gì bằng cách biến nó thành bất biến? Những vấn đề nào chúng ta sẽ gặp phải nếu C # 6 làm cho các đại biểu có thể thay đổi?

BIÊN TẬP

Tôi tin rằng sự bất biến sẽ ngăn chặn điều này:

ProcessBookDelegate thisIsATest = new ProcessBookDelegate(PrintTitle);

thisIsATest.ChangeTheDelegateInABadFashion();

someFunction(thisIsATest); //This function works as normal
                           //because the delegate is unchanged
                           //due to immutability

nhưng sự bất biến sẽ KHÔNG ngăn chặn điều này:

ProcessBookDelegate thisIsATest = new ProcessBookDelegate(PrintTitle);

thisIsATest = new ProcessBookDelegate(ChangeTheDelegateInABadFashion());

someFunction(thisIsATest); //This function works weird now because
                           //it expected the unchanged delegate

Tôi có đúng theo cách hiểu này không?

Câu trả lời:


15

Tôi nghĩ rằng bạn đang trộn lẫn những gì bất biến có nghĩa là.

Bất biến là gì

Hãy xem ví dụ này:

string s = "Hello";
s = "World";

stringbất biến? Đúng.
Điều này sẽ biên dịch? Đúng.
Chúng ta đã thay đổi chuỗi thể hiện chưa? Không .

Chúng tôi không thực hiện bất kỳ thay đổi để "Hello". Chúng tôi đang tạo một chuỗi, gán nó cho biến s, sau đó chúng tôi sẽ tạo một chuỗi mới string và ghi đè lên biến smới này string. Bất biến không đóng một phần ở đây.

Bất biến là gì

Nếu chúng ta đã thử một cái gì đó như thế này:

s.MutateInSomeWay();

trong đó MutateInSomeWaymột phương thức thay đổi chính chuỗi "Hello"(giá trị của s), sẽ không hợp lệ do tính bất biến của chuỗi.

Bất kỳ phương pháp stringnào thay đổi nó theo bất kỳ cách nào đều không thực sự thay đổi nó, họ đang tạo một cái mới stringvới giá trị đã thay đổi và trả lại cho người gọi.

nhưng sự bất biến sẽ KHÔNG ngăn chặn điều này:

ProcessBookDelegate thisIsATest = new ProcessBookDelegate(PrintTitle);  
thisIsATest = new ProcessBookDelegate(ChangeTheDelegateInABadFashion());
someFunction(thisIsATest); //This function works weird now because
//it expected the unchanged delegate

Tôi có đúng theo cách hiểu này không?

Có, tính bất biến sẽ không ngăn chặn được vì nó hoàn toàn hợp lệ, bạn không bị biến đổi bất kỳ đối tượng nào. Tất nhiên, bạn không hoàn toàn rõ ràng về những gì ChangeTheDelegateInABadFashion(), vì vậy thật khó để được cụ thể.


1
Đáng lưu ý rằng khía cạnh duy nhất của một đại biểu là bất biến là phương pháp sẽ được viện dẫn và danh tính của mục tiêu. Bản thân đối tượng đích thường sẽ có thể thay đổi (thực sự toàn bộ mục đích của nhiều đại biểu là làm biến đổi đối tượng đích!), Và ngay cả khi đại biểu giữ tham chiếu duy nhất đến một đối tượng mục tiêu, Func<int>việc trả lại 1 lần đầu tiên là hoàn toàn hợp pháp thời gian nó được gọi, 2 giây, v.v .-- điều này về cơ bản giống như một vật thể đột biến.
supercat

Bất biến xuất hiện khi bạn cố gắng sửa đổi chuỗi như thế này. s[2] = 't'.
M.kazem Akhÿ

Là một người chỉ cần chọn C #, tôi ước mình có thể chia sẻ câu trả lời của @ supercat ở đây với người khác. Thật vô nghĩa với tôi khi gọi các đại biểu là bất biến vì thực tế là họ có thể chứa mã tùy ý có thể có bất kỳ đột biến nào họ muốn, có thể nhìn thấy từ bên ngoài đại biểu.
trptcolin


2

Tôi tin rằng tiêu chuẩn an toàn; nếu bạn biết một đại biểu sẽ không bao giờ thay đổi thì bạn có thể đưa ra một số giả định về nó

đặc biệt bạn có thể yên tâm rằng một đoạn mã xấu không thể thay đổi đại biểu mà bạn đang chuyển đến một số chức năng (thậm chí là tình cờ)

điều này có thể gây ra khó khăn để theo dõi lỗi và khiến lập trình viên tự hỏi tại sao đại biểu của mình không được gọi


Vì các đại biểu có thể bị ràng buộc với các đối tượng có thể thay đổi, không có lý do gì để mong đợi rằng các cuộc gọi lặp lại cho cùng một đại biểu sẽ làm điều tương tự. Mặc dù vậy, bạn đã đúng về điểm an toàn của luồng: mục đích làm cho các đại biểu trở nên bất biến là để đảm bảo rằng họ luôn bị ràng buộc với một phương thức tương thích với kiểu của thể hiện đính kèm. Nếu phương thức và thể hiện có thể thay đổi riêng rẽ, điều tồi tệ có thể xảy ra.
supercat

2

Câu trả lời đơn giản là làm thay đổi một đại biểu có rất ít ý nghĩa. Một đại biểu rất nhiều tham chiếu đến một chức năng, một bộ mã thực thi. Đột biến cho thấy rằng bạn đang đột biến chức năng đó.

Hãy tự hỏi mình, phương pháp đó trên một đại biểu sẽ như thế nào, và sẽ làm gì? Theo một nghĩa nào đó, nó sẽ được viết lại mã của hàm đó. Điều đó mở ra một mức độ phức tạp rất lớn (gần như có thể thu được) đối với các đặc tả và triển khai trình biên dịch C # với rất ít lợi ích với chi phí hiệu năng lớn. Do đó hạn chế.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.