2010-02-19 13 views

Trả lời

12

Bạn sẽ phơi bày nó như một IEnumerable<T>, nhưng không chỉ trở về trực tiếp:

public IEnumerable<object> Objects { get { return obs.Select(o => o); } } 

Vì bạn chỉ ra bạn chỉ muốn traversal của danh sách, đây là tất cả các bạn cần.

Người ta có thể bị cám dỗ để trả lại List<object> trực tiếp như một IEnumerable<T>, nhưng điều đó sẽ không chính xác, bởi vì người ta có thể dễ dàng kiểm tra việc IEnumerable<T> lúc chạy, xác định nó là một List<T> và bỏ nó vào đó và biến những nội dung.

Tuy nhiên, bằng cách sử dụng return obs.Select(o => o); bạn sẽ trả về một trình lặp trên List<object>, không phải là tham chiếu trực tiếp đến chính số List<object>.

Một số người có thể nghĩ rằng điều này đủ điều kiện làm "biểu thức thoái hóa" theo mục 7.15.2.5 của Đặc tả ngôn ngữ C#. Tuy nhiên, Eric Lippert goes into detail as to why this projection isn't optimized away.

Ngoài ra, mọi người đề xuất sử dụng số AsEnumerable extension method. Điều này là không chính xác, vì danh tính tham chiếu của danh sách gốc được duy trì. Từ phần Nhận xét của tài liệu:

Phương thức AsEnumerable<TSource>(IEnumerable<TSource>) không có tác dụng khác ngoài việc thay đổi loại thời gian biên dịch của nguồn từ loại thực hiện IEnumerable<T> thành IEnumerable<T>.

Nói cách khác, tất cả những gì cần làm là truyền tham số nguồn thành IEnumerable<T>, không giúp bảo vệ tính toàn vẹn tham chiếu, tham chiếu gốc được trả về và có thể được chuyển trở lại List<T> và được sử dụng để thay đổi danh sách.

+2

Lưu ý rằng chúng tôi sẽ không bao giờ tối ưu hóa cuộc gọi * rõ ràng * để Chọn nếu điều đó xuất hiện trong mã của bạn. Chúng tôi sẽ tối ưu hóa cuộc gọi ngầm để Chọn khi chuyển biểu thức truy vấn thành các cuộc gọi phương thức. Nếu bạn nói "từ x trong y trong đó b chọn x" thì không có Chọn cuộc gọi, chỉ cần ở đâu. Nhưng nếu bạn nói "từ x trong y chọn x" thì chúng ta không chỉ tạo "y", chúng ta tạo ra một cuộc gọi chọn trên nó để đảm bảo tính bất biến của kết quả. Câu trả lời –

0

Bạn đã xem xét việc phát sinh một lớp học từ System.Collections.ReadOnlyCollectionBase?

11

Bạn có thể sử dụng ReadOnlyCollection hoặc tạo một bản sao của List và trả lại thay vì (xem xét hình phạt hoạt động của thao tác sao chép). Bạn cũng có thể sử dụng List<T>.AsReadOnly.

+0

chưa hoàn tất. mã xin vui lòng. –

1

Expose một ReadOnlyCollection<T>

+0

như thế nào? câu trả lời nghèo –

+1

Nó không chính xác là một vấn đề để làm cho người hỏi làm một chút săn bắn xung quanh. Kết quả đầu tiên trên Google làm cho nó rõ ràng như thế nào để lộ một 'ReadOnlyCollection '. – user7116

+0

sixlettervariables bạn rõ ràng là bỏ lỡ điểm của trang web. –

2

Bạn có thể làm điều này theo hai cách:

  1. Hoặc Bằng cách chuyển đổi danh sách thành một bộ sưu tập chỉ đọc:

    new System.Collections.ObjectModel.ReadOnlyCollection<object>(this.obs) 
    
  2. Hoặc bằng cách trả lại một IEnumerable của các mặt hàng:

    this.obs.AsEnumerable() 
    
2

Để giao diện của bạn thêm phương pháp chữ ký sau đây: công IEnumerable TraverseTheList()

implimented như vậy:

public IEnumerable<object> TraverseTheList() 
{ 

    foreach(object item in obj) 
    { 
     yield return item; 
    } 


} 

mà sẽ cho phép bạn làm như sau:

foreach(object item in Something.TraverseTheList()) 
{ 
// do something to the item 
} 

Lợi nhuận trả về cho trình biên dịch xây dựng một điều tra viên cho bạn.

+0

một góc khác; Xuất sắc. –

3

Điều này đã được nói, nhưng tôi không thấy bất kỳ câu trả lời nào là siêu rõ ràng.

Cách đơn giản nhất là chỉ cần trả về một ReadOnlyCollection

private List<object> objs; 

public ReadOnlyCollection<object> Objs { 
    get { 
     return objs.AsReadOnly(); 
    } 
} 

Hạn chế với điều này là, nếu bạn muốn thay đổi thực hiện của bạn sau này, sau đó một số người gọi có thể đã được phụ thuộc vào thực tế, rằng bộ sưu tập cung cấp quyền truy cập ngẫu nhiên. Vì vậy, một định nghĩa an toàn hơn là chỉ phơi bày một IEnumerable

public IEnumerable<object> Objs { 
    get { 
     return objs.AsReadOnly(); 
    } 
} 

Lưu ý rằng bạn không phải gọi AsReadOnly() để biên dịch mã này. Nhưng nếu bạn không làm như vậy, người gọi tôi chỉ cần truyền giá trị trả về trở lại một Danh sách và sửa đổi danh sách của bạn.

// Bad caller code 
var objs = YourClass.Objs; 
var list = objs as List<object>; 
list.Add(new object); // They have just modified your list. 

Điều này cũng vấn đề tiềm ẩn cũng tồn tại với giải pháp

public IEnumerable<object> Objs { 
    get { 
     return objs.AsEnumerable(); 
    } 
} 

này Vì vậy, tôi chắc chắn sẽ khuyên bạn nên gọi AsReadOnly() trên cho bạn danh sách, và trả lại giá trị đó.

+0

kết hợp tuyệt vời của đơn giản + an toàn. –

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