【问题标题】:IList with an implicit sort order具有隐式排序顺序的 IList
【发布时间】:2010-03-05 19:05:12
【问题描述】:

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

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

似乎最合乎逻辑/最有效的解决方案是将IList<Child> 公开为IEnumerable<Child>(以防止列表突变)并将显式添加/删除方法添加到包含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)

【问题讨论】:

    标签: linq ienumerable natural-sort


    【解决方案1】:

    使用SortedList&lt;&gt; 怎么样?

    【讨论】:

    • 这不起作用。如果更改底层对象中键的值,则排序顺序不会更改。
    【解决方案2】:

    您可以采取的一种方法是让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++;
        }
      }
    }
    

    【讨论】:

      【解决方案3】:

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

      编辑:

      如果这行得通,不幸的是,这并不容易。这家伙中的底层查找字典和底层 List 都没有排序,也没有足够暴露,以至于你可以替换它们。但是,它可能会提供一种模式供您在自己的实现中遵循。

      【讨论】:

        猜你喜欢
        • 2018-06-04
        • 2016-03-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-04
        • 2013-10-10
        • 2013-02-18
        相关资源
        最近更新 更多