Câu trả lời mới dựa trên câu trả lời của Hans
Nhờ câu trả lời mà Hans đưa ra, chúng ta có thể thấy việc thực hiện có phần phức tạp hơn chúng ta tưởng. Cả trình biên dịch và CLR đều rất cố gắng để tạo ấn tượng rằng kiểu mảng thực thi IList<T>
- nhưng phương sai mảng làm cho điều này phức tạp hơn. Trái ngược với câu trả lời từ Hans, các kiểu mảng (đơn chiều, dựa trên không) thực hiện trực tiếp các tập hợp chung, bởi vì kiểu của bất kỳ mảng cụ thể nào không phải System.Array
- đó chỉ là kiểu cơ sở của mảng. Nếu bạn hỏi một kiểu mảng mà nó hỗ trợ giao diện nào, thì nó sẽ bao gồm các kiểu chung:
foreach (var type in typeof(int[]).GetInterfaces())
{
Console.WriteLine(type);
}
Đầu ra:
System.ICloneable
System.Collections.IList
System.Collections.ICollection
System.Collections.IEnumerable
System.Collections.IStructuralComparable
System.Collections.IStructuralEquatable
System.Collections.Generic.IList`1[System.Int32]
System.Collections.Generic.ICollection`1[System.Int32]
System.Collections.Generic.IEnumerable`1[System.Int32]
Đối với mảng đơn chiều, mảng không dựa trên ngôn ngữ , mảng thực sự cũng thực hiện IList<T>
. Phần 12.1.2 của đặc tả C # nói như vậy. Vì vậy, bất cứ điều gì triển khai bên dưới làm, ngôn ngữ phải hoạt động như thể loại T[]
triển khai IList<T>
như với bất kỳ giao diện nào khác. Từ quan điểm này, giao diện được thực hiện với một số thành viên được thực hiện rõ ràng (chẳng hạn như Count
). Đó là lời giải thích tốt nhất ở cấp độ ngôn ngữ cho những gì đang xảy ra.
Lưu ý rằng điều này chỉ đúng đối với mảng đơn chiều (và mảng dựa trên 0, không phải ngôn ngữ C # nói bất cứ điều gì về mảng khác 0). T[,]
không thực hiện IList<T>
.
Từ góc độ CLR, một cái gì đó thú vị hơn đang diễn ra. Bạn không thể lấy ánh xạ giao diện cho các loại giao diện chung. Ví dụ:
typeof(int[]).GetInterfaceMap(typeof(ICollection<int>))
Đưa ra một ngoại lệ của:
Unhandled Exception: System.ArgumentException: Interface maps for generic
interfaces on arrays cannot be retrived.
Vì vậy, tại sao sự kỳ lạ? Chà, tôi tin rằng đó thực sự là do hiệp phương sai mảng, là một điểm yếu trong hệ thống loại, IMO. Mặc dù không phảiIList<T>
là hiệp phương sai (và không thể an toàn), hiệp phương sai của mảng cho phép điều này hoạt động:
string[] strings = { "a", "b", "c" };
IList<object> objects = strings;
... khiến nó trông giống như nông typeof(string[])
cụ IList<object>
, trong khi nó không thực sự.
Phân vùng 1 CLI spec (ECMA-335), mục 8.7.1, có điều này:
Kiểu chữ ký T tương thích với kiểu chữ ký U nếu và chỉ khi có ít nhất một trong các điều sau
...
T là một số không dựa trên cấp bậc-1 mảng V[]
, và U
là IList<W>
, và V là mảng phần tử tương thích với các W.
(Nó không thực sự đề cập đến ICollection<W>
hoặc IEnumerable<W>
mà tôi tin rằng đó là một lỗi trong thông số kỹ thuật.)
Đối với không có phương sai, thông số CLI trực tiếp đi cùng với thông số ngôn ngữ. Từ phần 8.9.1 của phân vùng 1:
Ngoài ra, một vectơ được tạo với kiểu phần tử T, triển khai giao diện System.Collections.Generic.IList<U>
, trong đó U: = T. (§8.7)
( Vectơ là một mảng đơn chiều với cơ số 0.)
Bây giờ trong điều khoản của chi tiết thực hiện , rõ CLR được làm một số bản đồ sôi nổi để giữ khả năng tương thích gán ở đây: khi một string[]
được yêu cầu để thực hiện ICollection<object>.Count
, nó không thể xử lý rằng trong khá theo cách thông thường. Điều này có được coi là triển khai giao diện rõ ràng không? Tôi nghĩ là hợp lý để xử lý nó theo cách đó, vì trừ khi bạn yêu cầu ánh xạ giao diện trực tiếp, nó luôn hoạt động theo cách đó từ góc độ ngôn ngữ.
Về ICollection.Count
thì sao?
Cho đến nay tôi đã nói về các giao diện chung, nhưng sau đó có những giao diện không chung ICollection
với thuộc tính của nó Count
. Lần này chúng ta có thể nhận được bản đồ giao diện và trên thực tế, giao diện được thực hiện trực tiếp bởi System.Array
. Tài liệu cho việc ICollection.Count
triển khai thuộc tính ở Array
các trạng thái rằng nó được triển khai với triển khai giao diện rõ ràng.
Nếu ai đó có thể nghĩ ra cách triển khai giao diện rõ ràng này khác với triển khai giao diện rõ ràng "bình thường", tôi rất vui được xem xét kỹ hơn.
Câu trả lời cũ xung quanh việc triển khai giao diện rõ ràng
Mặc dù ở trên, phức tạp hơn vì kiến thức về mảng, bạn vẫn có thể làm điều gì đó với các hiệu ứng hiển thị tương tự thông qua triển khai giao diện rõ ràng .
Đây là một ví dụ độc lập đơn giản:
public interface IFoo
{
void M1();
void M2();
}
public class Foo : IFoo
{
// Explicit interface implementation
void IFoo.M1() {}
// Implicit interface implementation
public void M2() {}
}
class Test
{
static void Main()
{
Foo foo = new Foo();
foo.M1(); // Compile-time failure
foo.M2(); // Fine
IFoo ifoo = foo;
ifoo.M1(); // Fine
ifoo.M2(); // Fine
}
}
Array
lớp học phải được viết bằng C #!