IList具有隐式排序顺序

时间:2010-03-05 19:05:12

标签: linq ienumerable natural-sort

我想创建一个IList<Child>,它始终以默认/隐式排序顺序维护其Child个对象(即无论对基础列表的添加/删除如何)。

我特别想避免的是,所有IList<Child>的所有消费者都需要在每次想要枚举它时明确调用IEnumerable<T>.OrderBy()。除了违反DRY之外,这样的方法也会破坏封装,因为消费者必须知道我的列表甚至是排序的,这实际上都不是他们的业务:)

似乎最符合逻辑/效率的解决方案是将IList<Child>公开为IEnumerable<Child>(以防止列表突变)并向包含Parent添加显式添加/删除方法。这样,我可以拦截需要重新排序的List的更改,并通过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 个答案:

答案 0 :(得分:1)

如何使用SortedList<>

答案 1 :(得分:0)

认为如果你从KeyedCollection派生,你就会得到你需要的东西。但这只是基于阅读文档。

修改

如果这样可行,不幸的是,这并不容易。基础查找字典和此人中的基础列表都没有排序,也没有足够暴露,以便您可以替换它们。但是,它可能会为您提供一种在您自己的实现中遵循的模式。

答案 2 :(得分:0)

您可以采用的一种方法是让Child发布一个事件OnStringPropertyChanged,该事件传递的是StringProperty之前的值。然后创建SortedList的派生,覆盖Add方法以将处理程序连接到该事件。每当事件触发时,从列表中删除该项并使用StringProperty的新值重新添加它。如果您无法更改Child,那么我将创建一个代理类,该代理类派生自或包装Child以实现该事件。

如果您不想这样做,我仍然会使用SortedList,但在StringProperty需要更改的任何时候内部管理上述排序逻辑。要成为DRY,最好通过一个正确管理排序的公共方法将所有更新路由到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++;
    }
  }
}