2009-03-06 30 views
19

Tôi có lớp sau đây:"Chỉ đọc" tài sản accessor trong C#

class SampleClass 
{ 
    private ArrayList mMyList; 

    SampleClass() 
    { 
     // Initialize mMyList 
    } 

    public ArrayList MyList 
    { 
     get { return mMyList;} 
    } 
} 

tôi muốn người dùng có thể nhận được mMyList đó là lý do tôi tiếp xúc với "nhận được" thông qua một tài sản tuy nhiên tôi không muốn thay đổi họ thực hiện cho đối tượng (ví dụ: MyList.Add (new Class());) để thực hiện theo cách của mình trở lại lớp học của tôi.

Tôi đoán tôi có thể trả lại bản sao của đối tượng nhưng có thể chậm và tôi đang tìm cách cung cấp lỗi biên dịch thông báo cho người dùng rằng họ không nên mong đợi có thể sửa đổi giá trị trả về từ Thuộc tính.

Điều này có khả thi không?

+0

câu hỏi liên quan: http://stackoverflow.com/question/681287/how-to-a-reference-type-property-readonly –

+2

Có 'Danh sách : ReadOnlyCollection ' trong .NET 4.5 thay đổi bất kỳ điều này? http://www.infoq.com/news/2011/10/ReadOnly-WInRT/ –

Trả lời

25

Với một ArrayList bạn bị giới hạn bởi vì không có lớp bộ sưu tập không chung chung chỉ đọc trong BCL. Giải pháp nhanh chóng và dơ bẩn là trả về một loại IEnumerable.

public IEnumerable MyList 
    { 
     get { return mMyList;} 
    } 

này sẽ không thực sự ngăn chặn ai đó từ đúc để ArrayList nhưng nó sẽ không cho phép chỉnh sửa theo mặc định hoặc

Bạn có thể trả về một danh sách một cách hiệu quả chỉ đọc bằng cách gọi ArrayList.ReadOnly. Tuy nhiên kiểu trả về của nó là một ArrayList để người dùng vẫn có thể biên dịch với .Thêm nhưng nó sẽ tạo ra một lỗi thời gian chạy.

1

Bạn nên bọc giá trị trả lại trong bộ sưu tập chỉ đọc.

19

Sử dụng phương thức ArrayList.ReadOnly() để tạo và trả về trình bao bọc chỉ đọc xung quanh danh sách. nó sẽ không sao chép danh sách, nhưng chỉ đơn giản là tạo một trình bao bọc chỉ đọc xung quanh nó. Để kiểm tra thời gian biên dịch, bạn có thể muốn trả về trình bao bọc chỉ đọc như IEnumerable như @Jared đề xuất.

public IEnumerable MyList 
{ 
    get { return ArrayList.ReadOnly(mMyList); } 
} 

Một bộ sưu tập đó là read-only là đơn giản là một bộ sưu tập với một wrapper có thể ngăn chặn điều chỉnh việc thu thập . Nếu các thay đổi được thực hiện cho bộ sưu tập cơ bản , bộ sưu tập chỉ đọc phản ánh những thay đổi đó.

Phương pháp này là hoạt động O (1).

Reference

+2

Tôi chống lại giải pháp này bởi vì nó biến những gì nên là một lỗi thời gian biên dịch thành một lỗi thời gian chạy. – JaredPar

+0

-1, OP: "Tôi đang tìm cách sẽ cung cấp lỗi ** thời gian biên dịch **" –

+0

Nếu không sao chép vào ReadOnlyCollection - điều mà anh ta cũng muốn tránh - tôi chọn thực thi read- chỉ hơn giả vờ là chỉ đọc. Làm cả hai thực sự có thể tốt hơn. – tvanfosson

-3

Chỉ cần chắc tài sản như Sealed (hoặc NotInheritable trong VB.NET) và chỉ đọc, như thế này:

public sealed readonly ArrayList MyList 
    { 
     get { return mMyList;} 
    } 

Cũng đừng quên để làm cho lĩnh vực sao lưu như readonly :

private readonly ArrayList mMyList; 

Nhưng để khởi tạo giá trị của mMyList, bạn phải khởi tạo CHỈ trong hàm tạo, một s trong ví dụ này:

public SampleClass() 
{ 
    // Initialize mMyList 
    mMyList = new ArrayList(); 
} 
10

Chỉ cần mở rộng câu trả lời của JaredPar. Như ông đã nói, việc trả lại trường sao lưu thực sự không hoàn toàn an toàn, vì người dùng vẫn có thể tự động gán IEnumerable quay lại ArrayList.

Tôi sẽ viết một cái gì đó như thế này để chắc chắn không có sửa đổi danh sách ban đầu được thực hiện:

public IEnumerable MyList 
{ 
    get 
    { 
     foreach (object o in mMyList) 
      yield return o; 
    } 
} 

Sau đó, một lần nữa, tôi sẽ probabily cũng sử dụng một danh sách chung (IEnumerable<T>) để được hoàn toàn loại an toàn.

+0

* Điều này * là đúng - ước gì tôi có thể bỏ phiếu hai lần. Bất kỳ vấn đề nào với việc không gọi là "phá vỡ năng suất;" sau vòng lặp? – Jay

+0

@Jay: Không cần thiết phải có "ngắt kết quả" rõ ràng, 'tại sau vòng lặp. Kết thúc của phương thức ngụ ý kết thúc của 'Enumerator' (và' MoveNext' sẽ trả về đúng 'false'). –

+0

Với giải pháp này, người dùng không bị mất chức năng của ArrayList như truy cập ngẫu nhiên nhanh và đếm nhanh? –

4

Sử dụng ReadOnlyCollection.

return new ReadOnlyCollection<object>(mMyList).

Bạn cũng có thể tạo trường ReadOnlyCollection và trường này sẽ tự động phản ánh các thay đổi trong danh sách cơ bản. Đây là giải pháp hiệu quả nhất.

Nếu bạn biết rằng mMyList chỉ chứa một loại đối tượng (ví dụ, nó không có gì ngoài DateTimes), bạn có thể trả lại ReadOnlyCollection<DateTime> (hoặc một số loại khác) để an toàn loại bổ sung. Nếu bạn đang sử dụng C# 3, bạn chỉ có thể viết

return new ReadOnlyCollection<DateTime>(mMyList.OfType<DateTime>().ToArray())

Tuy nhiên, điều này sẽ không tự động cập nhật danh sách bên dưới, và cũng có thể là kém hiệu quả (Nó sẽ sao chép toàn bộ danh sách) . Lựa chọn tốt nhất là làm cho mMyList một generic List<T> (ví dụ, một List<DateTime>)

0

liệu sẵn có từ NET v2.0

public ArrayList MyList { get; private set; } 
+0

Bạn vẫn có thể sử dụng Thêm trên danh sách hiện có. –

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