UPDATE: Tôi đã sử dụng câu hỏi này làm cơ sở cho một blog entry, ở đây:
http://blogs.msdn.com/ericlippert/archive/2009/09/24/why-is-covariance-of-value-typed-arrays-inconsistent.aspx
Xem blog ý kiến cho một cuộc thảo luận dài vấn đề này. Cảm ơn vì câu hỏi tuyệt vời của bạn!
Bạn đã tình cờ gặp một sự không nhất quán thú vị và không may giữa hệ thống loại CLI và hệ thống kiểu C#.
CLI có khái niệm "khả năng tương thích gán". Nếu giá trị x của kiểu dữ liệu đã biết S là "gán tương thích" với một vị trí lưu trữ cụ thể y của kiểu dữ liệu đã biết T, thì bạn có thể lưu trữ x trong y. Nếu không, thì làm như vậy không phải là mã có thể kiểm chứng và người xác minh sẽ không cho phép.
Hệ thống kiểu CLI cho biết, ví dụ, các kiểu con của kiểu tham chiếu được gán tương ứng với siêu kiểu của kiểu tham chiếu. Nếu bạn có một chuỗi, bạn có thể lưu nó trong một biến kiểu đối tượng, bởi vì cả hai là các kiểu tham chiếu và chuỗi là một kiểu con của đối tượng. Nhưng điều ngược lại không đúng; supertypes không được gán tương thích với các kiểu con. Bạn không thể dính cái gì đó chỉ được biết đến là đối tượng vào một biến kiểu chuỗi mà không đầu tiên đúc nó.
Về cơ bản "gán tương thích" có nghĩa là "có ý nghĩa khi gắn các bit chính xác này vào biến này". Việc gán từ giá trị nguồn tới biến đích phải là "bảo quản đại diện". Xem bài viết của tôi trên đó để biết chi tiết:
http://ericlippert.com/2009/03/03/representation-and-identity/
Một trong những quy tắc của CLI là "nếu X là nhiệm vụ tương thích với Y, sau đó X [] là nhiệm vụ tương thích với Y []".
Tức là, mảng là biến thể liên quan đến khả năng tương thích của bài tập. Đây thực sự là một loại hiệp phương sai; xem bài viết của tôi về điều đó để biết chi tiết.
http://blogs.msdn.com/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx
Đó không phải là quy tắc của C#. Quy tắc hiệp phương sai của mảng C# là "nếu X là kiểu tham chiếu ngầm chuyển đổi thành kiểu tham chiếu Y, thì X [] được chuyển đổi hoàn toàn thành Y []". Đó là một quy tắc khác biệt tinh tế, và do đó tình huống khó hiểu của bạn.
Trong CLI, uint và int tương ứng với nhiệm vụ. Nhưng trong C#, chuyển đổi giữa int và uint là EXPLICIT, chứ không phải IMPLICIT, và đây là các kiểu giá trị, không phải kiểu tham chiếu. Vì vậy, trong C#, nó không hợp pháp để chuyển đổi một int [] thành một uint [].
Nhưng nó là hợp pháp trong CLI. Vì vậy, bây giờ chúng tôi đang phải đối mặt với một sự lựa chọn.
1) Thực hiện "là" sao cho khi trình biên dịch không thể xác định câu trả lời tĩnh, nó thực sự gọi phương thức kiểm tra tất cả các quy tắc C# cho tính chuyển đổi bảo toàn danh tính. Điều này là chậm và 99,9% thời gian phù hợp với quy tắc CLR. Nhưng chúng tôi có hiệu suất đạt đến 100% tuân thủ các quy tắc của C#.
2) Thực hiện "là" sao cho khi trình biên dịch không thể xác định câu trả lời tĩnh, kiểm tra khả năng tương thích CLR cực nhanh, và sống với thực tế là uint [] là int [], mặc dù điều đó sẽ không thực sự hợp pháp trong C#.
Chúng tôi đã chọn cái sau. Thật không may là các thông số C# và CLI không đồng ý về điểm nhỏ này nhưng chúng tôi sẵn sàng sống với sự không thống nhất.
Đọc lớn. Cảm ơn câu trả lời. –
Xin chào Eric, ngoài sự tò mò, các bạn đã quyết định chấp nhận sự mâu thuẫn này hay chưa được dự đoán trước? Chỉ cần tự hỏi. –
Đã xóa bài đăng của tôi trong sự trì hoãn đến một câu trả lời tốt hơn và độc đáo hơn. – LBushkin