long x = 5000;
//Converting 64 bit data structure into a 32 bit, discarding the upper 32 bits.
int y = (int)x;
//Converting 32 bit data structure into a 64 bit.
long z = (long)y;
这些显式转换没有内置到系统中,因此必须以不同的方式完成。
public static Guid ToGuid(long value)
{
byte[] guidData = new byte[16];
Array.Copy(BitConverter.GetBytes(value), guidData, 8);
return new Guid(guidData);
}
public static long ToLong(Guid guid)
{
if (BitConverter.ToInt64(guid.ToByteArray(), 8) != 0)
throw new OverflowException("Value was either too large or too small for an Int64.");
return BitConverter.ToInt64(guid.ToByteArray(), 0);
}
显然,这个方法不应该用于通用的GUID,但只要GUID只有64位“实际数据”,就可以安全使用,确保这一点的最好方式是除非使用long创建了它们,否则不要在GUID上使用它。
作为预防措施,我添加了一个OverflowException,以防GUID在其最后64位存储任何非0值,因为生成的long不能转换回相同的GUID。
因此...
只要创建的GUID适合long,则可能吗?只有当超过long的指定大小时才出现问题,对吗?
是的...显然,GUID的相应long值不容易读取,以下是一些示例(long = guid):
1.340 = 0000053c-0000-0000-0000-000000000000
98.605 = 0001812d-0000-0000-0000-000000000000
149.957 = 000249c5-0000-0000-0000-000000000000
218.125.225 = 0d0053a9-0000-0000-0000-000000000000
4.249.596.910 = fd4bb3ee-0000-0000-0000-000000000000
23.139.913.545 = 633f0f49-0005-0000-0000-000000000000
9.223.372.036.854.775.807 = ffffffff-ffff-7fff-0000-000000000000
-9.223.372.036.854.775.808 = 00000000-0000-8000-0000-000000000000
-1 = ffffffff-ffff-ffff-0000-000000000000
是的,这些转换都是双向的,并且适用于您可以想到的任何长整型值...
但是因为您声明:
The Guid creation is outside of my control.
实际上极不可能实现这一点,相反,您拥有的 Guid 很可能是使用任何常见算法生成的,这将使 Guid 在此场景中无法使用。
现在是否有任何意义去做这个?...这需要对特定情况有深入了解,这是一个完全不同的讨论...
GUID是16字节长的。"长"通常被理解为64位(即8字节)长。你不能在不丢失或提供额外数据的情况下在它们之间进行转换。
我知道这个问题非常老,但它是谷歌的第一个搜索结果,我想提供我采用的答案。
Guid 不像其他已经说明的那样是 Int64,而是两个 UInt64。
我编写了一个 UInt128 类,其中包含一个高位和一个低位的 UInt64。从那里开始,你只需要在它们之间进行转换:
public static UInt128 ToUInt128(this Guid g)
{
var array = g.ToByteArray();
var hi = BitConverter.ToUInt64(array, 8);
var lo = BitConverter.ToUInt64(array, 0);
return new UInt128(hi, lo);
}
public static Guid ToGuid(this UInt128 i)
{
byte[] data = new byte[16];
Array.Copy(BitConverter.GetBytes(i.hi), 0, data, 8, 8);
Array.Copy(BitConverter.GetBytes(i.lo), 0, data, 0, 8);
return new Guid(data);
}
你可以将一个长整型(64位)映射成一个GUID(128位)。
但是你不能将一个GUID(128位)映射成一个长整型(64位)。
实际上,你需要的是将GUID映射成uint128(或int128)。
当然,将长整型映射成GUID时,需要在uint128的高部分补零。
你需要考虑的是GUID字节的特殊排序方式(每个字节的优先顺序),这样就可以像长整型(long=int64)一样进行范围比较。
为此,你需要查看以下回答:
SQL Server GUID sort algorithm
如何将long映射为ulong,将int映射为uint,请参见:
Mapping a ulong to a long in C#?
如何将UInt128转换为GUID,请参见GitHub上UInt128.cs中的ToGuidBytes()和ToGuid(),以及将长整型转换为UInt128,请参考UInt128.cs的构造函数。
public byte[] ToGuidBytes()
{
// byte[] ba = this.ToByteArrayLowToHighEnsured();
byte[] ba = this.ToByteArray(); // Fast
int[] guidByteOrder = new int[16] // 16 Bytes = 128 Bit
{10, 11, 12, 13, 14, 15, 8, 9, 6, 7, 4, 5, 0, 1, 2, 3};
// {00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15}
byte[] guidBytes = new byte[16];
for (int i = 0; i < 16; ++i)
{
guidBytes[guidByteOrder[15 - i]] = ba[i];
} // Next i
guidByteOrder = null;
ba = null;
return guidBytes;
} // End Function ToGuidBytes
public System.Guid ToGuid()
{
return new System.Guid(this.ToGuidBytes());
}
关于System.Guid.NewGuid()请参考“NextUInt128”:
以下是一些测试来验证/检查它的工作情况: BigIntUidTests.cs
Caveat emptor:
我不知道小端/大端机器会如何影响结果。
var guid = new Guid(ulong.MaxValue.ToString("00000000-0000-0000-0000-000000000000"));
并将其转换回来,如下:
var uint64 = Convert.ToUInt64(guid.ToString("N"))
您可以使用Guid
构造函数,这是一个简单但并非完美的示例:
Guid g1;
long g2;
// {00000001-0000-0000-0000-000000000000}
g1 = new Guid(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
// 00000001
g2 = Convert.ToInt64(g1.ToString().Split('-')[0]);
// 1 + 5 = 6
g2 += 5;
// {00000006-0000-0000-0000-000000000000}
g1 = new Guid((uint)g2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
4294967295
(int)的值。如果你需要更多,那么你必须使用另一个集合。public static Guid ToGuid(long value)
{
byte[] bytes = new byte[16];
BitConverter.GetBytes(value).CopyTo(bytes, 0);
return new Guid(bytes);
}
希望这段代码能对您有所帮助!!!