开发者

Forbid public Add and Delete for a List<T>

in my C#-project, I have a class which contains a List

public class MyClass
{
  public MyClass parent;
  public List<MyClass> children;
  ...
}

I want to prevent the user of the class f开发者_JS百科rom Adding (and Deleting) an Element to the children-List, but he shall still be able to parse its elements. I want to handle the Adding and Deleting within MyClass, providing an AddChild(MyClass item) and DeleteChild(MyClass item) to ensure that, when an item is added to the child list, the parent of that item will be set properly.

Any idea how to do this besides implementing my own IList?

Thanks in advance, Frank


If you hand the caller the List<T>, you can't control this; you can't even subclass List<T>, since the add/remove are not virtual.

Instead, then, I would expose the data as IEnumerable<MyClass>:

private readonly List<MyClass> children = new List<MyClass>();
public void AddChild(MyClass child) {...}
public void RemoveChild(MyClass child) {...}
public IEnumerable<MyClass> Children {
    get {
        foreach(var child in children) yield return child;
    }
}

(the yield return prevents them just casting it)

The caller can still use foreach on .Children, and thanks to LINQ they can do all the other fun things too (Where, First, etc).


Beside of implementing your own IList<T> you could return a ReadOnlyCollection<MyClass>.

public MyClass
{
    public MyClass Parent;

    private List<MyClass> children;
    public ReadOnlyCollection<MyClass> Children
    {
        get { return children.AsReadOnly(); }
    }
}


Expose the list as IEnumerable<MyClass>


Make the list private, and create public methods to access its content from outside the class.

public class MyClass
{
    public MyClass Parent { get; private set; }

    private List<MyClass> _children = new List<MyClass>();
    public IEnumerable<MyClass> Children
    {
        get
        {
            // Using an iterator so that client code can't access the underlying list
            foreach(var child in _children)
            {
                yield return child;
            }
        }
    }

    public void AddChild(MyClass child)
    {
        child.Parent = this;
        _children.Add(child);
    }

    public void RemoveChild(MyClass child)
    {
        _children.Remove(child);
        child.Parent = null;
    }
}

By the way, avoid declaring public fields, because you can't control what client code does with them.


using System.Collections.ObjectModel;

public class MyClass
{
    private List<MyClass> children;

    public ReadOnlyCollection<MyClass> Children
    {
        get
        {
            return new ReadOnlyCollection<MyClass>(children);
        }
    }
}


You don't need to reimplemented IList, just encapsulate a List in a class, and provide your own Add and Delete functions, that will take care of adding and setting the required properties.

You might have to create your own enumerator if you want to enumerate through the list though.


You can encapsulate the list in the class by making it private, and offer it as a ReadOnlyCollection:

public class MyClass {

  public MyClass Parent { get; private set; };

  private List<MyClass> _children;

  public ReadOnlyCollection<MyClass> Children {
    get { return _children.AsReadOnly(); }
  }

  public void AddChild(MyClass item) {
    item.Parent = this;
    _children.Add(item);
  }

  public void DeleteChild(MyClass item) {
    item.Parent = null;
    _children.Remove(item);
  }

}

You can make the Parent a property with a private setter, that way it can't be modified from the outside, but the AddChild and DeleteChild methods can change it.


Use List(T).AsReadOnly().

http://msdn.microsoft.com/en-us/library/e78dcd75.aspx

Returns a read-only IList<(Of <(T>)>) wrapper for the current collection.

Available since .NET 2.0.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜