IList с неявным порядком сортировки - PullRequest
3 голосов
/ 05 марта 2010

Я хотел бы создать 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 (который в данном случае является свойством, управляющим сортировкой). Должно быть более изящное решение такой основной проблемы, но я не смог ее найти.

EDIT: Я не был уверен, что предпочел бы совместимое с LINQ решение. Я бы предпочел не прибегать к использованию конструкций .NET 2.0 (т.е. SortedList)

Ответы [ 3 ]

1 голос
/ 05 марта 2010

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

0 голосов
/ 06 марта 2010

Один из способов сделать это - 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++;
    }
  }
}
0 голосов
/ 05 марта 2010

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

EDIT:

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

...