2008-09-10 29 views
13

tôi có một đối tượng trong một môi trường đa luồng duy trì một tập hợp các thông tin, ví dụ:bộ sưu tập Return như read-only

public IList<string> Data 
{ 
    get 
    { 
     return data; 
    } 
} 

Tôi hiện đang có return data; bọc bởi một ReaderWriterLockSlim để bảo vệ các bộ sưu tập từ việc chia sẻ vi phạm . Tuy nhiên, để chắc chắn gấp đôi, tôi muốn trả lại bộ sưu tập dưới dạng chỉ đọc, để mã gọi không thể thực hiện thay đổi đối với bộ sưu tập, chỉ xem những gì đã có ở đó. Đây có phải là ở tất cả có thể?

+0

Bạn cũng có thể muốn xem [readonlycollection-or-ienumerable-for-exposing-member-collections /] (http://stackoverflow.com/questions/491375/readonlycollection-or-ienumerable-for-exposing-member- bộ sưu tập/491591 # 491591) – nawfal

Trả lời

16

Nếu mục đích duy nhất của bạn là nhận mã gọi để không mắc lỗi và sửa đổi bộ sưu tập khi chỉ đọc tất cả những gì cần thiết là trả về giao diện không hỗ trợ Thêm, Xóa, v.v. Tại sao không trả lại IEnumerable<string>? Mã cuộc gọi sẽ phải truyền, điều mà họ không thể làm mà không biết nội bộ của thuộc tính mà họ đang truy cập.

Nếu bạn muốn ngăn chặn mã gọi từ việc quan sát cập nhật từ các chủ đề khác, bạn sẽ phải quay lại các giải pháp đã đề cập, để thực hiện bản sao sâu hoặc nông tùy thuộc vào nhu cầu của bạn.

+0

Âm thanh IEnumerable giống như một cách hay về phía trước. Như bạn đề nghị, ý định của tôi là chỉ bảo vệ bộ sưu tập khỏi sửa đổi trực tiếp; các thành viên trong bộ sưu tập sẽ không bị sửa đổi (hoặc cần sửa đổi). – alastairs

28

Nếu dữ liệu cơ bản của bạn được lưu trữ dưới dạng danh sách, bạn có thể sử dụng phương thức List(T).AsReadOnly.
Nếu dữ liệu của bạn có thể được liệt kê, bạn có thể sử dụng phương thức Enumerable.ToList để truyền bộ sưu tập của mình vào Danh sách và gọi AsReadOnly trên đó.

3

Bạn nên lưu ý rằng câu trả lời của aku sẽ chỉ bảo vệ danh sách khi chỉ đọc. Các yếu tố trong danh sách vẫn rất dễ ghi. Tôi không biết nếu có bất kỳ cách nào để bảo vệ các nguyên tố phi nguyên tử mà không nhân bản chúng trước khi đặt chúng vào danh sách chỉ đọc.

10

Tôi nghĩ bạn đang nhầm lẫn các khái niệm ở đây.

ReadOnlyCollection cung cấp trình bao bọc chỉ đọc cho bộ sưu tập hiện có, cho phép bạn (lớp A) chuyển tài liệu tham khảo đến bộ sưu tập an toàn trong trường hợp người gọi (Lớp B) không thể sửa đổi bộ sưu tập (tức là không thể thêm hoặc xóa bất kỳ yếu tố nào khỏi bộ sưu tập.)

Có hoàn toàn không có đảm bảo an toàn cho luồng.

  • Nếu bạn (Class A) tiếp tục sửa đổi bộ sưu tập cơ bản sau khi bạn trao nó ra như một ReadOnlyCollection sau đó lớp B sẽ thấy những thay đổi này, có bất kỳ vòng lặp không còn giá trị, vv và thường được mở cho bất kỳ thông thường các vấn đề đồng thời với các bộ sưu tập.
  • Ngoài ra, nếu các thành phần trong bộ sưu tập có thể thay đổi, cả bạn (Class A) người gọi (Lớp B) sẽ có thể thay đổi trạng thái có thể thay đổi của đối tượng trong bộ sưu tập.

triển khai của bạn phụ thuộc vào nhu cầu của bạn: - Nếu bạn không quan tâm đến người gọi (Class B) từ khi nhìn thấy bất kỳ thay đổi hơn nữa đến việc thu thập sau đó bạn chỉ có thể sao chép các bộ sưu tập, tay nó ra, và dừng lại quan tâm. - Nếu bạn chắc chắn cần người gọi (Lớp B) để xem các thay đổi được thực hiện cho bộ sưu tập và bạn muốn điều này an toàn cho luồng, thì bạn có nhiều vấn đề trên tay.Một khả năng là triển khai phiên bản ReadOnlyCollection của riêng bạn để cho phép truy cập bị khóa, mặc dù điều này sẽ không nhỏ và không thực hiện nếu bạn muốn hỗ trợ IEnumerable, và nó vẫn sẽ không bảo vệ bạn khỏi các yếu tố có thể thay đổi trong bộ sưu tập.

+0

Điểm tuyệt vời! +1 – nawfal

2

Thay vào đó, bạn có thể sử dụng bản sao của bộ sưu tập.

public IList<string> Data { 
get { 
    return new List<T>(data); 
}} 

Bằng cách đó, nó không quan trọng nếu nó được cập nhật.

2

Bạn muốn sử dụng từ khóa yield. Bạn lặp qua danh sách IEnumerable và trả về kết quả với yeild. Điều này cho phép người tiêu dùng sử dụng cho mỗi mà không sửa đổi bộ sưu tập.

Nó sẽ giống như thế này:

List<string> _Data; 
public IEnumerable<string> Data 
{ 
    get 
    { 
    foreach(string item in _Data) 
    { 
     return yield item; 
    } 
    } 
} 
19

Tôi đã bỏ phiếu cho câu trả lời chấp nhận và đồng ý với nó - tuy nhiên tôi có thể cung cấp cho bạn một cái gì đó để xem xét?

Không trả lại trực tiếp bộ sưu tập. Tạo một lớp logic kinh doanh được đặt tên chính xác phản ánh mục đích của bộ sưu tập.

Lợi thế chính của việc này là bạn không thể thêm mã vào bộ sưu tập để bất cứ khi nào bạn có một "bộ sưu tập" gốc trong mô hình đối tượng của mình, bạn luôn có mã hỗ trợ không phải OO trong toàn bộ dự án của mình để truy cập nó. Ví dụ:

Ví dụ: nếu bộ sưu tập của bạn là hóa đơn, bạn có thể có 3 hoặc 4 địa điểm trong mã mà bạn đã lặp qua các hóa đơn chưa thanh toán. Bạn có thể có phương thức getUnpaidInvoices. Tuy nhiên, sức mạnh thực sự xuất hiện khi bạn bắt đầu nghĩ về các phương thức như "payUnpaidInvoices (người thanh toán, tài khoản);".

Khi bạn vượt qua các bộ sưu tập thay vì viết một mô hình đối tượng, toàn bộ các lớp cấu trúc lại sẽ không bao giờ xảy ra với bạn.

Cũng lưu ý rằng điều này làm cho vấn đề của bạn đặc biệt tốt đẹp. Nếu bạn không muốn mọi người thay đổi bộ sưu tập, vùng chứa của bạn không cần có trình tắt. Nếu sau này bạn quyết định rằng chỉ trong một trường hợp bạn thực sự phải sửa đổi nó, bạn có thể tạo ra một cơ chế an toàn để làm như vậy.

Làm thế nào để bạn giải quyết vấn đề đó khi bạn đi qua một bộ sưu tập gốc?

Ngoài ra, không thể nâng cao bộ sưu tập gốc với dữ liệu bổ sung. Bạn sẽ nhận ra điều này trong lần tiếp theo bạn thấy rằng bạn chuyển vào (Collection, Extra) tới nhiều hơn một hoặc hai phương thức. Nó chỉ ra rằng "Extra" thuộc về đối tượng chứa bộ sưu tập của bạn.

+1

Câu trả lời hay, ước gì tôi có thể bỏ phiếu nhiều lần! – alastairs

+1

Không đồng ý. Miễn là mô hình miền là tốt, "trả tất cả các hóa đơn chưa thanh toán" hoặc các hoạt động tương tự là không đáng kể trong LINQ. Đưa logic vào các bộ sưu tập thường dẫn đến trách nhiệm smudged – DarkWanderer

+0

Và nơi nào bạn đề nghị đặt logic mà thao tác các trường hợp mulitple của một đối tượng từ nhiều nơi mà không cần sao chép và dán?Các hệ thống như Linq có thể đáng sợ bởi vì chúng làm cho nó dễ dàng như vậy để chỉ cần sao chép và dán một ít snip logic kinh doanh thay vì đặt nó ở đâu đó nó có thể được tái sử dụng. Bây giờ bạn đã có 10 bản sao của một lỗi nhỏ thay vì chỉ viết một phương pháp đơn giản. Khi bạn sửa lỗi, làm thế nào để bạn tìm thấy phần còn lại của chúng? Có thể tìm kiếm văn bản sẽ hoạt động, có thể không. KHÔNG BAO GIỜ sao chép logic nghiệp vụ, định nghĩa của DRY. Brevity không giống nhau. –

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