获取使用大端格式 C# 进行编码的 guid

Posted

技术标签:

【中文标题】获取使用大端格式 C# 进行编码的 guid【英文标题】:Get a guid to encode using big-endian formatting C# 【发布时间】:2018-06-17 06:39:41 【问题描述】:

我有一个不寻常的情况,我有一个使用二进制 (16) 主键的现有 mysql 数据库,这些是现有 api 中使用的 UUID 的基础。

我的问题是我现在想添加一个用 dotnet core 编写的替换 api,我遇到了编码问题,已经解释了 here

具体来说,dotnet 中的 Guid 结构使用混合端格式,生成与现有 api 不同的字符串。由于显而易见的原因,这是不可接受的。

所以我的问题是:有没有一种优雅的方法可以强制 Guid 结构完全使用大端格式编码?

如果没有,我可以写一个糟糕的 hack,但我想我会先咨询 SO 社区的集体智慧!

【问题讨论】:

【参考方案1】:

不;据我所知,没有内置的方法可以做到这一点。是的,Guid 目前有我只能称之为“crazy-endian”的实现。您需要获取Guid-ordered 位(通过unsafeGuid.ToByteArray),然后手动对它们进行排序,确定要反转哪些块 - 这不是简单的Array.Reverse()。所以:恐怕非常手动。我建议使用类似的 guid

00010203-0405-0607-0809-0a0b0c0d0e0f

调试它;这给了你(我怀疑你知道):

03-02-01-00-05-04-07-06-08-09-0A-0B-0C-0D-0E-0F

所以:

反向4 反向2 反向2 直8

【讨论】:

我担心可能是这种情况。这令人沮丧,因为虽然我不介意进行一些手动编码,但这会掩盖原本非常自我解释的代码。我想我只需要添加一些冗长的 cmets。不过感谢您的调试提示!【参考方案2】:

截至 2021 年,仍然没有内置方法可以将 System.Guid 转换为 C# 中与 MySQL 兼容的大端字符串。

这是我们在工作中遇到这个确切的 C# 混合端 Guid 问题时想出的扩展:

public static string ToStringBigEndian(this Guid guid)

    // allocate enough bytes to store Guid ASCII string
    Span<byte> result = stackalloc byte[36];

    // set all bytes to 0xFF (to be able to distinguish them from real data)
    result.Fill(0xFF);

    // get bytes from guid
    Span<byte> buffer = stackalloc byte[16];
    _ = guid.TryWriteBytes(buffer);

    int skip = 0;

    // iterate over guid bytes
    for (int i = 0; i < buffer.Length; i++)
    
        // indices 4, 6, 8 and 10 will contain a '-' delimiter character in the Guid string.
        // --> leave space for those delimiters
        if (i is 4 or 6 or 8 or 10)
        
            skip++;
        

        // stretch high and low bytes of every single byte into two bytes (skipping '-' delimiter characters)
        result[(2 * i) + skip] = (byte)(buffer[i] >> 0x4);
        result[(2 * i) + 1 + skip] = (byte)(buffer[i] & 0x0Fu);
    

    // iterate over precomputed byte array.
    // values 0x0 to 0xF are final hex values, but must be mapped to ASCII characters.
    // value 0xFF is to be mapped to '-' delimiter character.
    for (int i = 0; i < result.Length; i++)
    
        // map bytes to ASCII values (a-f will be lowercase)
        ref byte b = ref result[i];
        b = b switch
        
            0xFF => 0x2D,                // Map 0xFF to '-' character
            < 0xA => (byte)(b + 0x30u),  // Map 0x0 - 0x9 to '0' - '9'
            _ => (byte)(b + 0x57u)       // Map 0xA - 0xF to 'a' - 'f'
        ;
    

    // get string from ASCII encoded guid byte array
    return Encoding.ASCII.GetString(result);

它有点长,但除了返回的大端字符串之外,它没有堆分配,所以它保证很快:)

【讨论】:

以上是关于获取使用大端格式 C# 进行编码的 guid的主要内容,如果未能解决你的问题,请参考以下文章

大端与小端机器

大端BigEndian小端LittleEndian与字符集编码

大端格式 与 小端格式

flutter大端小端转换

转:大端模式和小段模式简述

为啥同时使用小端和大端?