如果目标是创建一个保留插入顺序的通用只读字典,可以使用SortedList<,>或SortedDictionary<,>实际上可以与IComparer一起使用<>尝试通过执行类似以下的操作来维护插入顺序?
class OrderedComparer<T> : IComparer<M>
{
public int Compare(M x, M y)
{
return x.Equals(y) ? 0 : -1;//or 1
}
}
SortedList<M> orderedList = new SortedList<M>(new OrderedComparer<T>());
(有趣的是,在SortedDictionary的情况下,上面的方法需要返回0或1以防止元素按反向插入顺序排序。)
答案 0 :(得分:5)
比较者必须遵守法律
Compare(a, b) == -Compare(b, a) //assuming only possible values are -1, 0, 1
这是symmetry property。您的示例代码不遵守它。因此BCL系列根本不给您任何保证。您违反了记录的合同。
你不能这样做。
相反,您可以将新字段添加到M
,并将广告订单存储为int
。然后,您可以在比较器中使用该字段。
答案 1 :(得分:3)
Compare
实施不遵循它应该遵循的rules of symmetry。这不是解决这个问题的正确方法。
对于按插入顺序排序的列表,只需使用List<T>
作为实现。另一方面,使用Dictionary<,>
,“返回项目的顺序未定义”。您可以将自己的IDictionary<,>
实现一起使用这两个类来完成您正在尝试的操作。
public class MyInsertionOrderDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private List<TKey> keysList;
private Dictionary<TKey, TValue> dict;
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
foreach (TKey key in keysList)
{
TValue value = dict[key];
yield return new KeyValuePair<TKey, TValue>(key, value);
}
}
// TODO implement interface
// when adding:
// keysList.Add(key);
// dict.Add(key, value);
// when removing:
// keysList.Remove(key);
// dict.Remove(key);
// you could also implement an indexer property like
public KeyValuePair<TKey, TValue> this[int index] { get { ... } }
}
这个类在外部非常类似于OrderedDictionary
类,但它是通用的。那里有other generic implementations。
答案 2 :(得分:0)
毫无疑问,你应该做这么可怕的事情。出于各种完美的理由,你绝对不应该这样:
现在,要实际知道您是否可以通过黑客攻击比较器保留SortedList中的插入顺序,只有一种方法:查看实现。反编译字节码,看看它是否可行。
事实证明,SortedList
使用二进制搜索,SortedDictionary
使用红黑树。
愚弄二进制搜索很容易。比较器仅用于比较新项目(如果您不删除任何内容)。总是返回1或-1,我总是忘记哪一个,并且你有一个未排序的列表。
对于红黑树,我不确定相同的技巧是否有效。我不记得那种树在重新平衡时是否必须使用比较器。如果确实如此,比较器无法提供有意义的结果可能会导致运行时错误,或者至多会导致复杂性保证丢失。但也许它真的很好。除此之外,我认为你仍然可以获得最大程度的再平衡。