Подтвердить что ты не робот

Запретить публикацию Добавить и удалить для списка <T>

в моем С# -проекте, у меня есть класс, который содержит List

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

Я хочу, чтобы пользователь класса не добавлял (и не удалял) элемент в список "Дети", но он все равно сможет разбирать его элементы. Я хочу обрабатывать добавление и удаление в MyClass, предоставляя элемент AddChild (элемент MyClass) и DeleteChild (элемент MyClass), чтобы гарантировать, что когда элемент будет добавлен в дочерний список, родительский элемент этого элемента будет установлен правильно.

Любая идея, как это сделать, помимо реализации моего собственного IList?

Спасибо заранее, Франк

4b9b3361

Ответ 1

Если вы передадите вызывающему абоненту List<T>, вы не можете управлять этим; вы даже не можете подкласса List<T>, так как add/remove не virtual.

Вместо этого я бы опубликовал данные как 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;
    }
}

(yield return предотвращает их просто литье)

Вызывающий может по-прежнему использовать foreach на .Children, и благодаря LINQ они могут выполнять все другие забавные вещи (Where, First и т.д.).

Ответ 2

Помимо реализации собственного IList<T>, вы можете вернуть ReadOnlyCollection<MyClass>.

public MyClass
{
    public MyClass Parent;

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

Ответ 3

Отобразите список как IEnumerable<MyClass>

Ответ 4

Сделать список приватным и создать общедоступные методы для доступа к его содержимому вне класса.

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;
    }
}

Кстати, избегайте объявления общедоступных полей, потому что вы не можете контролировать, что с ними делает клиентский код.

Ответ 5

using System.Collections.ObjectModel;

public class MyClass
{
    private List<MyClass> children;

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

Ответ 6

Вам не нужно переопределять IList, просто инкапсулируйте List в класс и предоставляйте свои собственные функции добавления и удаления, которые будут по-прежнему содержать и устанавливать необходимые свойства.

Возможно, вам придется создать свой собственный счетчик, если вы хотите перечислить список.

Ответ 7

Вы можете инкапсулировать список в классе, сделав его приватным, и предложите его как 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);
  }

}

Вы можете сделать свойство Parent a с приватным сеттером, таким образом его нельзя изменить извне, но методы AddChild и DeleteChild могут изменить его.

Ответ 8

Используйте List(T).AsReadOnly().

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

Возвращает только IL-код для чтения (Of < (T > ) > ) обертка для текущей коллекции.

Доступно с .NET 2.0.