Запретить публикацию Добавить и удалить для списка <T>
в моем С# -проекте, у меня есть класс, который содержит List
public class MyClass
{
public MyClass parent;
public List<MyClass> children;
...
}
Я хочу, чтобы пользователь класса не добавлял (и не удалял) элемент в список "Дети", но он все равно сможет разбирать его элементы. Я хочу обрабатывать добавление и удаление в MyClass, предоставляя элемент AddChild (элемент MyClass) и DeleteChild (элемент MyClass), чтобы гарантировать, что когда элемент будет добавлен в дочерний список, родительский элемент этого элемента будет установлен правильно.
Любая идея, как это сделать, помимо реализации моего собственного IList?
Спасибо заранее,
Франк
Ответы
Ответ 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.