我偶然发现了自定义 IComparer 实现的一些奇怪行为,似乎无法弄清楚如何纠正它并获得预期的行为。
我创建了一个静态类,为 System.Guid 提供了一个扩展方法,它允许用指定的 Int32 值覆盖 Guid 的前 4 个字节。这样做是为了允许创建对高人口数据库表索引友好的半顺序 Guid。
public static class GuidExt
{
public static Guid Sequence(this Guid obj, int index)
{
byte[] b = obj.ToByteArray();
BitConverter.GetBytes(index).CopyTo(b, 0);
return new Guid(b);
}
}
非常简单,并且完全按预期工作。
我创建的自定义 Comparer 类旨在允许 Guid 按 Guid 的插入 Int32 部分的升序排序。实现如下:
public class GuidSequenceComparer : IComparer<Guid>
{
public int Compare(Guid x, Guid y)
{
var xBytes = x.ToByteArray();
var yBytes = y.ToByteArray();
byte[] xIndexBytes = new byte[4];
for (int i = 0; i < 4; i++)
{
xIndexBytes[i] = xBytes[0];
}
byte[] yIndexBytes = new byte[4];
for (int i = 0; i < 4; i++)
{
yIndexBytes[i] = yBytes[i];
}
var xIndex = BitConverter.ToInt32(xIndexBytes, 0);
var yIndex = BitConverter.ToInt32(yIndexBytes, 0);
return xIndex.CompareTo(yIndex);
//// The following was used to test if any sort was being performed
//// and reverses the ordering (see below paragraph)
// if (xIndex > yIndex)
// {
// return -1;
// }
// if (xIndex < yIndex)
// {
// return 1
// }
// return 0;
}
}
当我在 List 上使用这个自定义比较器时,它会执行排序,但它会对 List 对象中的索引位置进行排序!不知道为什么会发生这种情况,但我通过反转比较结果来确认它,如注释掉的部分所示,它只是反转了列表的顺序,不是基于 Guid 中的 int 值,而是基于现有位置列表内。我完全不知道为什么会这样。
如果您想尝试重新创建行为,这是我在控制台应用程序中使用的简单测试。
List<Guid> guidList = new List<Guid>();
guidList.Add(Guid.NewGuid().Sequence(5));
guidList.Add(Guid.NewGuid().Sequence(3));
guidList.Add(Guid.NewGuid().Sequence(8));
guidList.Add(Guid.NewGuid().Sequence(1));
Console.WriteLine("unsorted:");
foreach (Guid item in guidList)
{
Console.WriteLine(item);
}
guidList.Sort(new GuidSequenceComparer());
Console.WriteLine("sorted:");
foreach (Guid item in guidList)
{
Console.WriteLine(item);
}
Console.ReadLine();