开发者

How to make List's Add method protected, while exposing List with get property?

I have a class named WhatClass that has List field in it. I need to be able to read-only this field, so I used a get property to expose it to other objects.

public class WhatClass
{
    List<SomeOtherClass> _SomeOtherClassItems;

    public List<SomeOtherClass> SomeOtherClassItems { get { return _SomeOtherClassItems; } }
}

However it turns out that any object can call

WhatClass.SomeOtherClassIt开发者_StackOverflow社区ems.Add(item);

How can I prevent this?


As others have said, you are looking for the .AsReadOnly() extension method.

However, you should store a reference to the collection instead of creating it during each property access:

private readonly List<SomeOtherClass> _items;

public WhatClass()
{
    _items = new List<SomeOtherClass>();

    this.Items = _items.AsReadOnly();
}

public ReadOnlyCollection<SomeOtherClass> Items { get; private set; }

This is to ensure that x.Items == x.Items holds true, which could otherwise be very unexpected for API consumers.

Exposing ReadOnlyCollection<> communicates your intent of a read-only collection to consumers. Changes to _items will be reflected in Items.


You're looking for the ReadOnlyCollection<T> class, which is a read-only wrapper around an IList<T>.

Since the ReadOnlyCollection<T> will reflect changes in the underlying list, you don't need to create a new instance every time.

For example:

public class WhatClass {
    public WhatClass() {
        _SomeOtherClassItems = new List<SomeOtherClass>();
        SomeOtherClassItems = _SomeOtherClassItems.AsReadOnly();
    }

    List<SomeOtherClass> _SomeOtherClassItems;

    public ReadOnlyCollection<SomeOtherClass> SomeOtherClassItems { get; private set; }
}


Use List<T>.AsReadOnly:

public ReadOnlyCollection<SomeOtherClass> SomeOtherClassItems
{
    get
    {
        return _SomeOtherClassItems.AsReadOnly();
    }
}

This will return a ReadOnlyCollection, which will throw an exception if a client calls Add through the interface. In addition, the ReadOnlyCollection type does not expose a public Add method.


How about using AsReadOnly()? - MSDN Documentation


List<T> implements IReadOnlyList<T> since .NET Framework 4.5, so an internal list can be exposed as IReadOnlyList<T> instead for that purpose.

public class WhatClass
{
    List<SomeOtherClass> _SomeOtherClassItems;

    public IReadOnlyList<SomeOtherClass> SomeOtherClassItems => _SomeOtherClassItems;
}


You can just use ToList() to return a copy of the list instead. Other classes can do what they like to the copy it won't alter your original list.

You should make it clear in the name that they are getting a copy.

using System.Linq;

public class WhatClass
{
    List<SomeOtherClass> _SomeOtherClassItems;

    public List<SomeOtherClass> SomeOtherClassItems { get { return _SomeOtherClassItems.ToList(); } }
}


Although others have pointed out the use of ReadOnlyCollection, it's worth noting that there also exists a cool ReadOnlyObservableCollection. It can be really useful in bindings and view models. As pointed here:

This class is a read-only wrapper around an ObservableCollection. If changes are made to the underlying collection, the ReadOnlyObservableCollection reflects those changes. To be notified of the changes to this class, subscribe to the CollectionChanged or PropertyChanged event.

You can simply expose this ReadOnlyObservableCollection and make changes to the underlying collection and rest assured that your view is getting updated.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜