C# 将整数的可视表示形式视为十六进制以放置在guid中

C# 将整数的可视表示形式视为十六进制以放置在guid中,c#,.net,C#,.net,我们有一个遗留需求,即将现在新迁移的intID值存储到guid类型中,以用于ID不可知的数据类型(基本上是旧代码,它利用了guid的“全局唯一”部分,以便在一列/字段中包含所有可能的ID) 由于这一要求,后续要求以人类可读的方式将实体的整数ID嵌入guid。这很重要,目前正是这一点阻止了我直接针对字节值进行操作 目前,我有以下几点: public static byte[] IntAsHexBytes(int value) { return BitConverte

我们有一个遗留需求,即将现在新迁移的
int
ID值存储到
guid
类型中,以用于ID不可知的数据类型(基本上是旧代码,它利用了
guid
的“全局唯一”部分,以便在一列/字段中包含所有可能的ID)

由于这一要求,后续要求以人类可读的方式将实体的整数ID嵌入
guid
。这很重要,目前正是这一点阻止了我直接针对字节值进行操作

目前,我有以下几点:

    public static byte[] IntAsHexBytes(int value)
    {
        return BitConverter.GetBytes(Convert.ToInt64(value.ToString(), 16));
    }

    public static Guid EmbedInteger(int id)
    {
        var ib = IntAsHexBytes(id);

        return new Guid(new byte[]
            {
                0,0,0,0,0,0,1,64,ib[7],ib[6],ib[5],ib[4],ib[3],ib[2],ib[1],ib[0]
            });
    }
它将
int
的可视表示形式视为十六进制值(
value.ToString()
),将其转换为
long
Convert.ToInt64(value.ToString(),16)
),并将
long
中的字节抓取为展平的
字节[]
用于在特定结构中创建
guid

因此,给定一个42的
int
,当您将42视为十六进制并将其转换为
long
时,您将得到66,并将66的字节放入
guid
中:

"00000000-0000-4001-0000-000000000042"
"00000000-0000-4001-0000-000379932126"
379932126
int
给出:

"00000000-0000-4001-0000-000000000042"
"00000000-0000-4001-0000-000379932126"
因此,最终的结果是将整数放入最后12位的
guid
,使其看起来像整数42(即使基础整数值是66)

这比使用串联构造字符串以输入
newguid(string)
构造函数快大约30%-40%,但我觉得我缺少了一个解决方案,它可以避免首先对字符串进行任何操作

所涉及的实际时间安排非常小,因此作为性能改进,可能无法证明所做的努力是合理的

这纯粹是为了我自己的好奇心,看看是否有更快的方法来解决这个问题。我在这里发帖是因为我是一个长期的SO用户,但我很困惑这是否是一个代码审查的问题,虽然我没有直接要求对我的代码做任何事情,但它只是演示了我想要什么作为输出

提供的整数范围为0到
int.MaxValue

更新:为了完整性,这是我们目前拥有的,也是我正在测试的:

string s = string.Format("00000000-0000-4001-0000-{0:D12}", id);
return new Guid(s);
我上面的其他代码比这个快30%左右。

我想这会满足您的要求。不确定它是否比您的代码更高效,但至少要短一点。:)


它的工作原理是使用数字格式12:D12,该格式使输入数字在字段宽度为12且前导为零的情况下被格式化为十进制。

好的,下面是另一个完全避免字符串的版本。希望这会更好。:)

Adam Houldsworth:更新:此代码也可以展开:

int remainder = id % 100;
bytes[0] = (byte)(16 * (remainder / 10) + remainder % 10);
id /= 100;
if (id == 0) return;
remainder = id % 100;
bytes[1] = (byte)(16 * (remainder / 10) + remainder % 10);
id /= 100;
if (id == 0) return;
remainder = id % 100;
bytes[2] = (byte)(16 * (remainder / 10) + remainder % 10);
id /= 100;
if (id == 0) return;
remainder = id % 100;
bytes[3] = (byte)(16 * (remainder / 10) + remainder % 10);
id /= 100;
if (id == 0) return;
remainder = id % 100;
bytes[4] = (byte)(16 * (remainder / 10) + remainder % 10);

我一定错过了什么重要的事情。如果您将整数的十进制表示形式视为十六进制,那么当您通过Convert.ToInt32(value,base)解析它时,您肯定会得到溢出?我只是不明白我想。。。但是IntAsHexBytes(int.MaxValue)肯定会引发异常。@MatthewWatson通过将guid转换为字符串、对其进行子字符串化以获取最后一节并将其提供给
int.Parse
,将返回值提取为整数。我们不再这样做了,因为有人找到了一种直接针对字节的方法来提取整数,但没有人找到与我上面的代码相反的替代方法。如果你认真对待输入范围是0到int.MaxValue,那么你的代码就不会工作。但是,当你说你向Int.Parse()提供了最后一部分(如果是字符串形式,则可能是最后8个十六进制数字?)时,你将其解析为十六进制,是吗?@MatthewWatson修订,很好-当我在纸上思考时,我得出了相同的结论,十六进制的结果整数值在
Int.MaxValue
之前溢出了一段时间。我的计时代码只有1000000。当你在计时时,你能举一个整数大于99的例子吗?我认为输入123456应该将以下内容放在GUID字符串的末尾:-000000123456。这是正确的吗?这实际上是我们目前所拥有的,它的效率略低于我上面所发布的。虽然我不确定是格式调用还是guid字符串构造函数负责。我认为OP实际上是想避免使用以字符串作为参数的构造函数,因为性能原因。+1我必须进行您所做的编辑,在得到您的编辑之前,我离线进行了编辑,但这大大缩短了时间。“很多”是主观的。第一个解决方案需要550ms,我的解决方案需要300ms,你的解决方案需要100ms,但是你发现了神奇的数学,42->66:DJust作为一个旁白,你只需要一个
字节[5]
就可以把
int.MaxValue
作为十六进制整数。我也不需要发布提取ID的代码,因为它的计算结果看起来很像这样,正好相反。这正是我想要的。我对你的另一个答案有+1,尽管它不是我想要的。如果你在循环中调用它,你可能会对优化它非常挑剔,在循环外创建byte[]数组,并将其传递到EmbedInteger()方法中,以避免重复创建数组。;)我变得非常挑剔,并使用了字节,而不是数组:-)