IList с неявным порядком сортировки
Я хотел бы создать IList<Child>
что поддерживает его Child
объекты в порядке по умолчанию / неявной сортировке всегда (т.е. независимо от добавления / удаления в базовый список).
Чего я конкретно пытаюсь избежать, так это потребности всех потребителей IList<Child>
явно вызывать IEnumerable<T>.OrderBy()
каждый раз, когда они хотят перечислить это. Помимо нарушения DRY, такой подход также нарушил бы инкапсуляцию, так как потребители должны были бы знать, что мой список даже отсортирован, что на самом деле не их дело:)
Решение, которое казалось наиболее логичным / эффективным, заключалось в IList<Child>
как IEnumerable<Child>
(чтобы предотвратить мутации List) и добавить явные методы Add/Remove к содержащему Parent
, Таким образом, я могу перехватить изменения в Списке, которые требуют пересортировки, и применить их через Linq:
public class Child {
public string StringProperty;
public int IntProperty;
}
public class Parent{
private IList<Child> _children = new List<Child>();
public IEnumerable<Child> Children{
get
{
return _children;
}
}
private void ReSortChildren(){
_children = new List<Child>(child.OrderBy(c=>c.StringProperty));
}
public void AddChild(Child c){
_children.Add();
ReSortChildren()
}
public void RemoveChild(Child c){
_children.Remove(c);
ReSortChildren()
}
}
Тем не менее, этот подход не перехватывает изменения, внесенные в основной Child.StringProperty
(что в данном случае является собственностью, управляющей сортировкой). Должно быть более изящное решение такой основной проблемы, но я не смог ее найти.
РЕДАКТИРОВАТЬ: Я не был уверен, что я бы предпочел LINQ-совместимое решение. Я бы предпочел не прибегать к использованию конструкций.NET 2.0 (т.е. SortedList)
3 ответа
Один из способов сделать это - Child
опубликовать событие OnStringPropertyChanged
который проходит по предыдущему значению StringProperty
, Затем создайте вывод SortedList
который отменяет Add
метод для подключения обработчика к этому событию. Всякий раз, когда происходит событие, удалите элемент из списка и повторно добавьте его с новым значением StringProperty. Если вы не можете изменить Child
, тогда я бы сделал прокси-класс, который либо наследует, либо оборачивает Child
реализовать мероприятие.
Если вы не хотите этого делать, я бы все равно использовал SortedList
, но внутренне управляйте вышеуказанной логикой сортировки в любое время StringProperty
должен быть изменен. Чтобы быть СУХИМ, желательно направлять все обновления на StringProperty
через общий метод, который правильно управляет сортировкой, вместо того, чтобы обращаться к списку напрямую из различных мест в классе и дублировать логику управления сортировкой.
Я бы также предостерег от того, чтобы разрешить контроллеру передавать ссылку на Child
, что позволяет ему манипулировать StringProperty
после того, как он добавлен в список.
public class Parent{
private SortedList<string, Child> _children = new SortedList<string, Child>();
public ReadOnlyCollection<Child> Children{
get { return new ReadOnlyCollection<Child>(_children.Values); }
}
public void AddChild(string stringProperty, int data, Salamandar sal){
_children.Add(stringProperty, new Child(stringProperty, data, sal));
}
public void RemoveChild(string stringProperty){
_children.Remove(stringProperty);
}
private void UpdateChildStringProperty(Child c, string newStringProperty) {
if (c == null) throw new ArgumentNullException("c");
RemoveChild(c);
c.StringProperty = newStringProperty;
AddChild(c);
}
public void CheckSalamandar(string s) {
if (_children.ContainsKey(s))
var c = _children[s];
if (c.Salamandar.IsActive) {
// update StringProperty through our method
UpdateChildStringProperty(c, c.StringProperty.Reverse());
// update other properties directly
c.Number++;
}
}
}
Я думаю, что если вы наследуете KeyedCollection, вы получите то, что вам нужно. Это основано только на чтении документации.
РЕДАКТИРОВАТЬ:
Если это сработает, к сожалению, это будет нелегко. Ни базовый поисковый словарь, ни нижележащий список в этом парне не отсортирован, и они недостаточно раскрыты, чтобы их можно было заменить. Тем не менее, он может предоставить шаблон для вашей собственной реализации.