.NET本地化GUID转换

6

我有一个外部数据库,它向我提供信息。其中一个将其数据保存为本地GUID格式,而另一个数据源则提供标准的.NET GUID格式字符串。

有没有一种简洁的方法可以将本地GUID转换为 GUID结构

还有,有没有验证位来确定提供的值是否为本地GUID?如果有的话,我似乎找不到。

两者之间的区别如下:

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

Data1、Data2和Data3的字节顺序被颠倒,但Data4保持不变。更多信息请参见http://en.wikipedia.org/wiki/Globally_unique_identifier

1
抱歉,我不明白 - 有什么区别吗?无论如何,GUID不只是16个字节的数据吗? - Rup
1
GUID的前8个字节可以改变它们的字节序,但在.NET中似乎没有一种清晰的方式来接受具有反转顺序的数据。更多信息请参见:https://dev59.com/JnI-5IYBdhLWcg3w18Z3 - Seph
谢谢,我从未见过这个。我一直以为字节序像IP那样是强制规定的。我认为对于本机情况,编写自己的十六进制字符串解析器可能是最简单的方法。 - Rup
1
位序反转似乎非常不可能。字节顺序可能,但仍然有些牵强。最终,数据提供者负责进行此转换。联系供应商获取支持。不要排除您用于查看数据库表的任何查看器中存在错误的可能性。 - Hans Passant
3个回答

17

要判断输入是否为小端模式,可以使用BitConverter.IsLittleEndian()函数。

我之前也需要执行同样的操作,采用了Paul Smith上面提供的答案,并在此基础上进行了改进,修正了最后一个字节交换的顺序,并将其简化为一次翻转,确保guid.FlipEndian().FlipEndian() == guid。

C# 代码:

public static class Extensions
{
    /// <summary>
    /// A CLSCompliant method to convert a big-endian Guid to little-endian
    /// and vice versa.
    /// The Guid Constructor (UInt32, UInt16, UInt16, Byte, Byte, Byte, Byte,
    ///  Byte, Byte, Byte, Byte) is not CLSCompliant.
    /// </summary>
    [CLSCompliant(true)]
    public static Guid FlipEndian(this Guid guid)
    {
        var newBytes = new byte[16];
        var oldBytes = guid.ToByteArray();

        for (var i = 8; i < 16; i++)
            newBytes[i] = oldBytes[i];

        newBytes[3] = oldBytes[0];
        newBytes[2] = oldBytes[1];
        newBytes[1] = oldBytes[2];
        newBytes[0] = oldBytes[3];
        newBytes[5] = oldBytes[4];
        newBytes[4] = oldBytes[5];
        newBytes[6] = oldBytes[7];
        newBytes[7] = oldBytes[6];

        return new Guid(newBytes);
    }
}

VB.net代码(从在线服务翻译):

导入 System.Runtime.CompilerServices

Module ModuleExtension

    ''' <summary>
    ''' A CLSCompliant method to convert a big-endian Guid to little-endian
    ''' and vice versa.
    ''' The Guid Constructor (UInt32, UInt16, UInt16, Byte, Byte, Byte, Byte,
    '''  Byte, Byte, Byte, Byte) is not CLSCompliant.
    ''' </summary>
    <Extension()>
    Public Function FlipEndian(guid As Guid) As Guid
        Dim newBytes = New Byte(15) {}
        Dim oldBytes = guid.ToByteArray()

        For i As Integer = 8 To 15
            newBytes(i) = oldBytes(i)
        Next

        newBytes(3) = oldBytes(0)
        newBytes(2) = oldBytes(1)
        newBytes(1) = oldBytes(2)
        newBytes(0) = oldBytes(3)
        newBytes(5) = oldBytes(4)
        newBytes(4) = oldBytes(5)
        newBytes(6) = oldBytes(7)
        newBytes(7) = oldBytes(6)

        Return New Guid(newBytes)
    End Function

End Module

2
我在使用LINQ从MySQL中提取Binary(16) UUID时遇到了同样的问题(GUID的后两部分如预期一样,但前两个片段不同)。这个函数恢复了我的理智。谢谢。 - sobelito
@Maverik 你确定顺序吗?我认为应该是:3 2 1 0 5 4 7 6。 - Andrés Falcón
@Andres 自从我发布这个以来,它一直在为我工作。我刚刚使用它查询活动目录,距离我上次阅读这个理论已经太久了,我记不起来翻转的顺序了。 - Maverik
@Andres - 我认为,实质上就像你所建议的那样。如果您查看 oldBytes 的数组下标,它会按照 5 7 6 的顺序进行,这将产生您期望的结果。 - Mr Moose
使用Array.Reverse()会简单得多,如下所示:var bytes = guid.ToByteArray(); Array.Reverse(bytes, 0, 4); Array.Reverse(bytes, 4, 2); Array.Reverse(bytes, 6, 2); return bytes; - hIpPy
只需在原地重新排列字节。无需使用另一个byte[]缓冲区。请参阅https://stackoverflow.com/questions/9195551/why-does-guid-tobytearray-order-the-bytes-the-way-it-does/77080208#77080208 - undefined

1

0

如果你确实在处理字节序问题,那么你别无选择,只能自己解析字符串成Guid的组成部分,切换字节序,然后创建一个Guid并使用它。


我想我得自己编写一个包装器来反转这些值。 - Seph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接