我想创建一个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)
答案 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++;
}
}
}