你可以构建这样的东西(从this answer by Jon Skeet借用代码)
public sealed class IdentityEqualityComparer<T> : IEqualityComparer<T>
where T : class
{
public int GetHashCode(T value) => RuntimeHelpers.GetHashCode(value);
public bool Equals(T left, T right) => left == right;
}
public class StableComparer : IComparer
{
private readonly Dictionary<object, int> _itemsPosition =
new Dictionary<object, int>(new IdentityEqualityComparer<object>());
private readonly IComparer _baseComparer;
public StableComparer(IEnumerable collection, IComparer baseComparer)
{
_baseComparer = baseComparer;
int index = 0;
foreach (object item in collection)
{
_itemsPosition.Add(item, index);
index++;
}
}
public int Compare(object x, object y)
{
int baseResult = _baseComparer.Compare(x, y);
if (baseResult != 0)
{
return baseResult;
}
int xIndex = _itemsPosition[x];
int yIndex = _itemsPosition[y];
return xIndex.CompareTo(yIndex);
}
}
(我添加了相等比较器部分以确保按照@PeterDuniho 的建议使用引用相等)。
这段代码可以这样使用:
class Item
{
public int Id { get; }
public string Description { get; }
public Item(int id, string description)
{
Id = id;
Description = description;
}
}
class ItemComparer : IComparer
{
public int Compare(object x, object y) => ((Item)x).Id.CompareTo(((Item)y).Id);
}
和
class Program
{
static void Main(string[] args)
{
var items = new ArrayList()
{
new Item(1, "Item 0 (1)"),
new Item(3, "Item 1 (3)"),
new Item(2, "Item 2 (2)"),
new Item(3, "Item 3 (3)"),
new Item(1, "Item 4 (1)"),
new Item(4, "Item 5 (4)"),
new Item(1, "Item 6 (1)")
};
Console.WriteLine("Not stable");
SortAndDisplay((ArrayList)items.Clone(), new ItemComparer());
Console.WriteLine("Stable");
SortAndDisplay((ArrayList)items.Clone(),
new StableComparer(items, new ItemComparer()));
}
static void SortAndDisplay(ArrayList items, IComparer comparer)
{
items.Sort(comparer);
foreach (var item in items)
{
Console.WriteLine(((Item)item).Description);
}
}
}
请注意,框架 4.5 中的 Sort 发生了变化,这可以改变“相等”项目的顺序。如果我在 Framework 4 中运行此代码,我会得到:
Not stable
Item 6 (1)
Item 4 (1)
Item 0 (1)
Item 2 (2)
Item 3 (3)
Item 1 (3)
Item 5 (4)
Stable
Item 0 (1)
Item 4 (1)
Item 6 (1)
Item 2 (2)
Item 1 (3)
Item 3 (3)
Item 5 (4)
我尝试将此代码发布到 .net Fiddle,但它不允许使用框架 4。
您也可以使用稳定的Linq's OrderBy。