GUID比较古怪

时间:2015-01-16 17:01:08

标签: c# .net guid

.NET有两种GUID数据类型:Guid,用于命令"自然"中的GUID。方式和SqlGuid,它考虑最后一个破折号后的六个字节是最重要的。这种差异在此详细解释:MSDN: Comparing GUID and uniqueidentifier Values

但是,在这两种情况下,应该保持以下内容(假设所有...都相等):

57d0affe-... < 57d0afff-... < 57d0b000-...

如果是这种情况,为什么我会得到以下输出(见注释)?

using System;
using System.Data.SqlTypes;

class Program
{
    static void Main(string[] args)
    {
        var g1 = new SqlGuid("57d0affe-9d9d-11e4-bec2-e840f2ad1632");
        var g2 = new SqlGuid("57d0afff-9d9d-11e4-bec2-e840f2ad1632");
        var g3 = new SqlGuid("57d0b000-9d9d-11e4-bec2-e840f2ad1632");

        Console.WriteLine(g1 < g2); // prints True
        Console.WriteLine(g2 < g3); // prints False <- ?
        Console.ReadLine();
    }
}

我的理解是g2 < g3也应该产生True。我是否误解了某些内容,或者这是框架中的一些错误?使用普通Guid代替SqlGuid时,输出为True两倍,如预期的那样。

2 个答案:

答案 0 :(得分:2)

实际上,比较是逐字节进行的。所以你要问的第一件事是&#34; 0xff是否小于0x00?&#34;显然,它不是:)

这当然是为什么SQL guid符号是&#34;怪异的&#34; - 它&#34;两次倒转&#34;。我不知道为什么MS SQL中的uniqueidentifier决定这样做(我假设它允许更好的散列或其他东西),但SqlGuid必须具有相同的行为,所以它只获取整个byte[]并逐个接一个字节。第一个字节是第一个字节的最后一个字节,第二个字节是第一个字节的倒数第二个字节等。

修改

要添加更多信息,Microsoft标准GUID结构定义如下:

typedef struct _GUID {
  DWORD Data1;
  WORD  Data2;
  WORD  Data3;
  BYTE  Data4[8];
} GUID;

当使用逐字节比较时,前三个组获得native-endianness,而最后一个组始终是big-endian。

这是SQL Server中使用的GUID,也是SqlGuid模拟的GUID。原生.NET System.Guid在其CompareTo方法中执行相同的操作。

RFCC 4122 GUID实际上在big-endian机器上显示相同的行为,唯一的区别是它始终是所有组的大端。据我所知,它根本没有描述任何设计的排序。

比较GUID,除了相等之外并没有多大意义。如果您需要这样做,那么有特殊的GUID(如顺序或基于时间的GUID)可以让您更合理地分配值,同时仍然具有合理的独特性。

由于它没有定义,并且它没有太多意义,逐字节比较或char-by-char是最明显的两个 - 人类期望char-by -char,因为我们看到了这个值,但对于计算机来说,逐字节更合理。但是,更为合理的是逐场调查 - 以及那里发生的事情。

答案 1 :(得分:2)

比较有点复杂。

首先定义了一些订单:

  private static readonly int[] x_rgiGuidOrder = new int[16]
    {10, 11, 12, 13, 14, 15, 8, 9, 6, 7, 4, 5, 0, 1, 2, 3};

然后有这个方法

private static EComparison Compare(SqlGuid x, SqlGuid y) {
        //Swap to the correct order to be compared
        for (int i = 0; i < SizeOfGuid; i++) {
            byte    b1, b2;

            b1 = x.m_value [x_rgiGuidOrder[i]];
            b2 = y.m_value [x_rgiGuidOrder[i]];
            if (b1 != b2)
                return(b1 < b2) ? EComparison.LT : EComparison.GT;
        }
        return EComparison.EQ;
    } 

然而,这不是整个故事,究竟是什么原因是来自字符串的构造函数:

    public SqlGuid(String s) {
        m_value = (new Guid(s)).ToByteArray();
    }

它创建一个新的GUID,然后使用它的字节表示。

这给了我们以下字节值:

g2 : 255 175 208 87 157 157 228 17 190 194 232 64 242 173 22 50
g3 : 0   176 208 87 157 157 228 17 190 194 232 64 242 173 22 50

我们可以看到255大于0而不是相反。

您可以找到完整的来源here 如何获得字节表示是here