3

我想创建一个始终以默认/隐式排序顺序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)

4

3 回答 3

1

使用一个怎么样SortedList<>

于 2010-03-05T19:07:03.967 回答
0

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

编辑:

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

于 2010-03-05T19:21:53.233 回答
0

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

如果您不想这样做,我仍然会使用 a ,但在需要更改时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++;
    }
  }
}
于 2010-03-05T21:24:27.937 回答