Вы можете построить что-то вроде этого (заимствуя код из этого ответа у Джона Скита )
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);
}
}
}
Обратите внимание, что в Sort 4.5 произошли изменения, которые могут изменить порядок «равных» предметов. Если я запускаю этот код в 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, но он не позволяет использовать framework 4. Вы можете использовать OrderBy Linq тоже стабильный.