2009-09-11 21 views
11

Có mã này ...Có điều gì kỳ diệu về ReadOnlyCollection

var b = new ReadOnlyCollection<int>(new[] { 2, 4, 2, 2 }); 
b[2] = 3; 

tôi nhận được một lỗi biên dịch tại dòng thứ hai. Tôi mong đợi một lỗi thời gian chạy từ ReadOnlyCollection<T> thực hiện IList<T>this[T] có thiết lập trong giao diện IList<T>.

Tôi đã cố gắng sao chép chức năng của ReadOnlyCollection, nhưng việc xóa setter khỏi this[T] là lỗi biên dịch.

Trả lời

16

Các indexer được thực hiện với rõ ràng thực hiện giao diện, vì vậy bạn sẽ chỉ có thể truy cập vào nó nếu bạn làm:

IList<int> b = new ReadOnlyCollection<int>(new[] { 2, 4, 2, 2 }); 
b[2] = 3; 

hoặc

var b = new ReadOnlyCollection<int>(new[] { 2, 4, 2, 2 }); 
((IList<int>)b)[2] = 3; 

Tất nhiên, nó sau đó sẽ thất bại ở thời gian thực hiện ...

này là hoàn toàn có chủ ý và hữu ích - nó có nghĩa là khi trình biên dịch biết đó là một ReadOnlyCollection, các bit không được hỗ trợ chức năng không có sẵn với bạn, giúp chuyển hướng bạn khỏi lỗi thời gian thực hiện.

Đây là một bước thú vị và tương đối bất thường, hiệu quả thực hiện một nửa thuộc tính/chỉ mục ngầm và một nửa rõ ràng.

Trái ngược với suy nghĩ trước đây của tôi, tôi tin rằng ReadOnlyCollection<T>thực thực hiện toàn bộ indexer một cách rõ ràng, nhưng cũng cung cấp một indexer readonly công cộng.Nói cách khác, nó là một cái gì đó như thế này:

T IList<T>.this[int index] 
{ 
    // Delegate interface implementation to "normal" implementation 
    get { return this[index]; } 
    set { throw new NotSupportedException("Collection is read-only."); } 
} 

public T this[int index] 
{ 
    get { return ...; } 
} 
+0

Ok, nhưng làm thế nào để tôi sao chép chức năng của ReadOnlyCollection bằng cách sử dụng thực hiện rõ ràng. Tôi không thấy làm thế nào bạn có thể loại bỏ một phương pháp hoặc tài sản từ giao diện. –

+0

@EsbenP: Bạn không thể xóa một phương thức khỏi giao diện ... nhưng bạn có thể làm cho nó chỉ khả dụng khi kiểu tĩnh của tham chiếu là giao diện chứ không phải lớp thực hiện giao diện. –

+0

Ok, nếu tôi có hai bộ chỉ mục, một trong số họ thực hiện IList rõ ràng nó hoạt động T IList .Đây [int index] { được { nguồn trở lại [index]; } đặt { ném mới NotImplementedException(); } } công khai T [int index] { nhận { nguồn trả về [index]; } } –

2

Nó triển khai thực hiện IList.Items một cách rõ ràng, làm cho nó không công khai, và bạn sẽ phải truyền đến giao diện để tiếp tục triển khai và thực hiện một chỉ mục mới [...], được sử dụng thay thế, mà chỉ có một get-accessor.

Nếu bạn bỏ bộ sưu tập vào IList, mã của bạn sẽ biên dịch, nhưng sẽ thất bại trong thời gian chạy thay thế.

Đáng tiếc là tôi không biết làm thế nào để làm điều này trong C#, vì viết một indexer trong C# bao gồm việc sử dụng từ khóa this, và bạn không thể viết này:

T IList<T>.this[int index] { get; set; } 
+0

@Lasse: Bạn có thể viết đó - với việc triển khai phù hợp. Vấn đề là bạn không thể thực hiện một nửa một cách rõ ràng và một nửa ngầm, theo như tôi có thể nói. –

+0

Bạn không cần phải, nếu bạn có thể viết điều đó, bạn viết setter với chỉ ném một ngoại lệ, và sau đó bạn thực hiện một công cộng này [..] indexer chỉ với getter. –

1

Không có ma thuật, các ReadOnlyCollection chỉ có việc thực hiện khác nhau cho indexer riêng của nó và indexer mà thực hiện giao diện IList<T>:

public T Item[int index] { get; } 

T IList<T>.Item[int index] { get; set; } 

Nếu bạn cast danh sách của bạn để IList<int>, bạn sẽ nhận được lỗi thời gian chạy thay vì lỗi biên dịch:

((IList<int>)b)[2] = 3; 

Chỉnh sửa:
Để thực hiện indexer trong lớp học của riêng bạn, bạn sử dụng this keyword:

public T this[int index] { get { ... } } 

T IList<T>.this[int index] { get { ... } set { ... } } 
+0

Đó cũng là suy nghĩ của tôi, nhưng khi tôi thử điều đó trong lớp học của riêng tôi thực hiện IList nó sẽ không biên dịch –

+0

Thông báo lỗi biên dịch là gì? – thecoop

+0

@EsbenP: Để thực hiện nó trong một lớp, cú pháp không giống như chữ ký được hiển thị trong tài liệu. Xem chỉnh sửa ở trên. – Guffa

Các vấn đề liên quan