为什么 Guid.ToByteArray() 以这种方式对字节进行排序?

问题描述 投票:0回答:2

当您在 .NET 中对 GUID 调用

ToByteArray()
时,与 GUID 的字符串表示形式相比,结果数组中字节的顺序不是您所期望的。例如,对于以下表示为字符串的 GUID:

11223344-5566-7788-9900-aabbccddeeff

ToByteArray()
的结果是这样的:

44, 33, 22, 11, 66, 55, 88, 77, 99, 00, AA, BB, CC, DD, EE, FF

注意前四个字节的顺序是相反的。此外,字节 4 和 5 也被交换,字节 6 和 7 也被交换。但最后 8 个字节的顺序与字符串中表示的顺序相同。

我知道这种情况正在发生。我想知道为什么 .NET 以这种方式处理它。

作为参考,您可以在这里这里看到一些对此的讨论和困惑(错误归因于Oracle数据库)。

c# .net guid
2个回答
34
投票

如果您阅读 GUID 构造函数中的 示例部分,您将找到答案:

Guid(1,2,3,new byte[]{0,1,2,3,4,5,6,7})
创建一个对应于
"00000001-0002-0003-0001-020304050607"
的 Guid。

a
是一个32位整数,
b
是一个16位整数,
c
是一个16位整数,
d
只是8个字节。

由于

a
b
c
是整数类型而不是原始字节,因此在选择如何显示它们时,它们会受到字节顺序的影响。 GUID 的 RFC (RFC4122) 指出它们应该以大端格式呈现。


0
投票

我为此编写了一个扩展方法,

byte[] ToByteArrayMatchingStringRepresentation(Guid)
,它使用
BitConverter
考虑字节顺序,并就地更改顺序。

using System;

namespace rm.Extensions;

/// <summary>
/// Guid extensions.
/// </summary>
public static class GuidExtension
{
    /// <summary>
    /// Returns a 16-element byte array that contains the value of this instance
    /// matching its string representation (endian-agnostic).
    /// <para></para>
    /// See https://stackoverflow.com/questions/9195551/why-does-guid-tobytearray-order-the-bytes-the-way-it-does
    /// <remarks>
    /// <para></para>
    /// Note: The byte[] returned by <see cref="ToByteArrayMatchingStringRepresentation(Guid)"/> will not yield
    /// the original Guid with <see cref="Guid(byte[])"/> ctor.
    /// </remarks>
    /// </summary>
    public static byte[] ToByteArrayMatchingStringRepresentation(this Guid guid)
    {
        var bytes = guid.ToByteArray();
        TweakOrderOfGuidBytesToMatchStringRepresentation(bytes);
        return bytes;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="Guid"></see> structure by using the specified array of bytes
    /// matching its string representation (endian-agnostic).
    /// <para></para>
    /// See https://stackoverflow.com/questions/9195551/why-does-guid-tobytearray-order-the-bytes-the-way-it-does
    /// <remarks>
    /// <para></para>
    /// Note: The Guid returned by <see cref="ToGuidMatchingStringRepresentation(byte[])"/> will not yield
    /// the original byte[] with <see cref="Guid.ToByteArray()"/>.
    /// </remarks>
    /// </summary>
    public static Guid ToGuidMatchingStringRepresentation(this byte[] bytes)
    {
        _ = bytes ??
            throw new ArgumentNullException(nameof(bytes));
        if (bytes.Length != 16)
        {
            throw new ArgumentException("Length should be 16.", nameof(bytes));
        }
        TweakOrderOfGuidBytesToMatchStringRepresentation(bytes);
        return new Guid(bytes);
    }

    private static void TweakOrderOfGuidBytesToMatchStringRepresentation(byte[] guidBytes)
    {
        if (BitConverter.IsLittleEndian)
        {
            Array.Reverse(guidBytes, 0, 4);
            Array.Reverse(guidBytes, 4, 2);
            Array.Reverse(guidBytes, 6, 2);
        }
    }
}

来源:https://github.com/rmandvikar/csharp-extensions/blob/dev/src/rm.Extensions/GuidExtension.cs

© www.soinside.com 2019 - 2024. All rights reserved.