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

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

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

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

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

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

【问题讨论】:

    标签: c# mysql .net-core guid asp.net-core-webapi


    【解决方案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);
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-18
      • 1970-01-01
      • 2010-10-09
      • 2013-06-30
      • 2020-10-10
      • 2014-03-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多