通过将4个较小的数字基本类型编码为long (Int64)来生成唯一键
本文关键字:Int64 long 一键 唯一 编码 类型 4个 数字 | 更新日期: 2023-09-27 17:53:42
我有以下方法应该为所提供的参数的任何组合创建一个唯一的long:
private static long GenerateKey(byte sT, byte srcT, int nId, ushort aId)
{
var nBytes = BitConverter.GetBytes(nId);
var aBytes = BitConverter.GetBytes(aId);
var byteArray = new byte[8];
Buffer.BlockCopy(new[] { sT}, 0, byteArray, 7, 1);
Buffer.BlockCopy(new[] { srcT}, 0, byteArray, 6, 1);
Buffer.BlockCopy(aBytes, 0, byteArray, 4, 2);
Buffer.BlockCopy(nBytes, 0, byteArray, 0, 4);
var result = BitConverter.ToInt64(byteArray, 0);
return result;
}
最后是:
1 2 3 4 5 6 7 8
------------------------------------
|byte|byte| ushort | int |
------------------------------------
这可以用位操作来完成吗?我尝试了下面的方法,但似乎为不同的值生成相同的数字??
var hash = ((byte)sT << 56) ^ ((byte)srcT<< 48) ^ (aId << 32) ^ nId;
出问题的地方是这样的
((byte)sT << 56)
不是你想要的。它实际做的是将sT
转换为byte
(它已经是),然后它被隐式转换为int
(因为你用它做数学运算),然后它向左移位24(移位计数被屏蔽以限制它们小于左操作数的大小)。
所以你应该转换成宽类型,而不是窄类型,像这样:
((long)sT << 56)
另外,请注意,隐式地将int
转换为long
符号扩展它,这意味着如果nId
是负的,您最终将补充所有其他字段(xor与所有1是互补的)。
那么试试这个:
((long)sT << 56) | ((long)srcT << 48) | ((long)aId << 32) | (nId & 0xffffffffL)
我还把"或"改成了"或",这在组合不重叠的东西时更习惯。
下一行:
var hash = ((byte)sT << 56) ^ ((byte)srcT<< 48) ^ (aId << 32) ^ nId;
你移动的位数超过了类型所能容纳的位数。你不能移动byte
超过8位,其余的都丢失了。相反,ushort
不能移位超过16位。只需将所有内容转换为long
,您将得到预期的结果:
var hash = ((long)sT << 56)
^ ((long)srcT << 48)
^ ((long)aId << 32)
^ (uint)nId; // Cast to uint is required to prevent sign extension