Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 由于某些原因,自定义IComparer实现未按预期排序_C#_.net_Generics - Fatal编程技术网

C# 由于某些原因,自定义IComparer实现未按预期排序

C# 由于某些原因,自定义IComparer实现未按预期排序,c#,.net,generics,C#,.net,Generics,我偶然发现了自定义IComparer实现的一些奇怪行为,似乎不知道如何纠正它并获得预期的行为 List<Guid> guidList = new List<Guid>(); guidList.Add(Guid.NewGuid().Sequence(5)); guidList.Add(Guid.NewGuid().Sequence(3)); guidList.Add(Guid.NewGuid().Sequen

我偶然发现了自定义IComparer实现的一些奇怪行为,似乎不知道如何纠正它并获得预期的行为

        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();
我创建了一个静态类,为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);
    }
}
非常直截了当,工作完全符合预期

我创建的自定义比较器类旨在允许按照Guid插入的Int32部分的升序对Guid进行排序。实施情况如下:

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;
    }
}
公共类GuidSequenceComparer:IComparer
{
公共整数比较(Guid x,Guid y)
{
var xBytes=x.ToByteArray();
var yBytes=y.ToByteArray();
字节[]xIndexBytes=新字节[4];
对于(int i=0;i<4;i++)
{
xIndexBytes[i]=xBytes[0];
}
字节[]yIndexBytes=新字节[4];
对于(int i=0;i<4;i++)
{
yIndexBytes[i]=yBytes[i];
}
var xIndex=BitConverter.ToInt32(xIndexBytes,0);
var yIndex=BitConverter.ToInt32(yIndexBytes,0);
返回xIndex.CompareTo(yIndex);
////以下内容用于测试是否正在执行任何排序
////并反转顺序(参见下面的段落)
//如果(xIndex>yIndex)
// {
//返回-1;
// }
//if(xIndex
当我在列表上使用这个自定义比较器时,它确实执行排序,但它在列表对象中对索引位置进行排序!不知道为什么会发生这种情况,但我通过颠倒比较结果(如注释掉的部分所示)来确认,它只是颠倒了列表的顺序,不是基于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();
List guidList=newlist();
添加(Guid.NewGuid().Sequence(5));
添加(Guid.NewGuid().Sequence(3));
添加(Guid.NewGuid().Sequence(8));
guidList.Add(Guid.NewGuid().Sequence(1));
Console.WriteLine(“未排序:”);
foreach(guidList中的Guid项)
{
控制台写入线(项目);
}
Sort(新的GuidSequenceComparer());
Console.WriteLine(“排序:”);
foreach(guidList中的Guid项)
{
控制台写入线(项目);
}
Console.ReadLine();

在您的比较器中,我认为

        xIndexBytes[i] = xBytes[0];
应该是

        xIndexBytes[i] = xBytes[i];
不确定这是否是问题所在,但这正是我时常遇到的事情:-)

User@Magnus击败了我,但您可以使用该函数避免复制循环,如下所示:

Array.Copy(xBytes, 0, xIndexBytes, 0, 4);

我会优化你的比较

public int Compare(Guid x, Guid y)
{
    var xBytes = x.ToByteArray();
    var yBytes = y.ToByteArray();
    int result = 0;
    for (int i = 0; i < 4; i++)
    {
        var result = xBytes[i].CompareTo(yBytes[i]);
        if (result != 0)
        {
            break;
        }
    }

    return result;
}

或者这个怎么样,不需要复制

public static Guid Sequence(this Guid source, int index)
{
    var buffer = source.ToByteArray();
    return new Guid(
        index,
        BitConvertor.ToInt16(buffer, 4),
        BitConvertor.ToInt16(buffer, 6),
        buffer[8],
        buffer[9],
        buffer[10],
        buffer[11],
        buffer[12],
        buffer[13],
        buffer[14],
        buffer[15]);
}

您可能想考虑将扩展方法调整为:

public static class GuidExt
{
    public static Guid Sequence(this Guid g, int sequenceNum)
    {
        var bytes = g.ToByteArray();

        BitConverter.GetBytes(sequenceNum).CopyTo(bytes, 0);

        return new Guid(bytes);
    }

    public static int GetSequenceNum(this Guid g)
    {
        return BitConverter.ToInt32(g.ToByteArray(), 0);
    }
}
在你的方法中有很多你不需要的额外旋转。有趣的是,这就是Jalayn发现的错误的根源

然后,您可以更改比较器以执行更简单的操作:

public int Compare(Guid x, Guid y)
{
    return x.GetSequenceNum().CompareTo(y.GetSequenceNum());
}

希望这有帮助。

标识列有什么问题?
xBytes[0]
在循环中似乎不正确。哈哈,是的,我完全忽略了这一点。这就是问题所在,现在一切正常。啊,孩子,深夜的代码狂欢…@MikeJohnson你也可以写
xBytes.CopyTo(xIndexBytes,0)
并跳过循环。@Magnus提出了提高性能的极好建议。谢谢。哈哈哇。。。非常感谢。去喝杯咖啡,羞愧地垂下头。。。没问题,很乐意帮助:-)+1非常优雅的解决方案。我喜欢这些建议。清除了相当一部分不必要的开销。谢谢:)