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

Как насчет использования SortedList<>?

Я думаю, что если вы наследуете KeyedCollection, вы получите то, что вам нужно. Это основано только на чтении документации.

РЕДАКТИРОВАТЬ:

Если это сработает, к сожалению, это будет нелегко. Ни базовый поисковый словарь, ни нижележащий список в этом парне не отсортирован, и они недостаточно раскрыты, чтобы их можно было заменить. Тем не менее, он может предоставить шаблон для вашей собственной реализации.

Другие вопросы по тегам