我一直在寻找一种可靠的方法来执行Guid到2长度的转换以及解决方法,主要是为了获得一种向外部服务提供跟踪ID的简单方法。
目标是获得一种可逆的方式来传递单个参数2 longs,然后将其解码回来(当然它不打算在另一侧使用“解码”)。它就像是外部服务的会话ID。
答案 0 :(得分:2)
警告:这些解决方案不考虑字节顺序,因此结果可能因平台而异:
利用C#7的新功能,我推出了以下工具类,它将long,ulong,int,uint转换为Guid并反转:
public static class GuidTools
{
public static Guid GuidFromLongs(long a, long b)
{
byte[] guidData = new byte[16];
Array.Copy(BitConverter.GetBytes(a), guidData, 8);
Array.Copy(BitConverter.GetBytes(b), 0, guidData, 8, 8);
return new Guid(guidData);
}
public static (long, long) ToLongs(this Guid guid)
{
var bytes = guid.ToByteArray();
var long1 = BitConverter.ToInt64(bytes, 0);
var long2 = BitConverter.ToInt64(bytes, 8);
return (long1, long2);
}
public static Guid GuidFromULongs(ulong a, ulong b)
{
byte[] guidData = new byte[16];
Array.Copy(BitConverter.GetBytes(a), guidData, 8);
Array.Copy(BitConverter.GetBytes(b), 0, guidData, 8, 8);
return new Guid(guidData);
}
public static (ulong, ulong) ToULongs(this Guid guid)
{
var bytes = guid.ToByteArray();
var ulong1 = BitConverter.ToUInt64(bytes, 0);
var ulong2 = BitConverter.ToUInt64(bytes, 8);
return (ulong1, ulong2);
}
public static Guid GuidFromInts(int a, int b, int c, int d)
{
byte[] guidData = new byte[16];
Array.Copy(BitConverter.GetBytes(a), guidData, 4);
Array.Copy(BitConverter.GetBytes(b), 0, guidData, 4, 4);
Array.Copy(BitConverter.GetBytes(c), 0, guidData, 8, 4);
Array.Copy(BitConverter.GetBytes(d), 0, guidData, 12, 4);
return new Guid(guidData);
}
public static (int, int , int, int) ToInts(this Guid guid)
{
var bytes = guid.ToByteArray();
var a = BitConverter.ToInt32(bytes, 0);
var b = BitConverter.ToInt32(bytes, 4);
var c = BitConverter.ToInt32(bytes, 8);
var d = BitConverter.ToInt32(bytes, 12);
return (a, b, c, d);
}
public static Guid GuidFromUInts(uint a, uint b, uint c, uint d)
{
byte[] guidData = new byte[16];
Array.Copy(BitConverter.GetBytes(a), guidData, 4);
Array.Copy(BitConverter.GetBytes(b), 0, guidData, 4, 4);
Array.Copy(BitConverter.GetBytes(c), 0, guidData, 8, 4);
Array.Copy(BitConverter.GetBytes(d), 0, guidData, 12, 4);
return new Guid(guidData);
}
public static (uint, uint, uint, uint) ToUInts(this Guid guid)
{
var bytes = guid.ToByteArray();
var a = BitConverter.ToUInt32(bytes, 0);
var b = BitConverter.ToUInt32(bytes, 4);
var c = BitConverter.ToUInt32(bytes, 8);
var d = BitConverter.ToUInt32(bytes, 12);
return (a, b, c, d);
}
}
还发现了另一个受到启发的解决方案:Converting System.Decimal to System.Guid
[StructLayout(LayoutKind.Explicit)]
struct GuidConverter
{
[FieldOffset(0)]
public decimal Decimal;
[FieldOffset(0)]
public Guid Guid;
[FieldOffset(0)]
public long Long1;
[FieldOffset(8)]
public long Long2;
}
private static GuidConverter _converter;
public static (long, long) FastGuidToLongs(this Guid guid)
{
_converter.Guid = guid;
return (_converter.Long1, _converter.Long2);
}
public static Guid FastLongsToGuid(long a, long b)
{
_converter.Long1 = a;
_converter.Long2 = b;
return _converter.Guid;
}
答案 1 :(得分:0)
以下两种方法可以满足您的需求:
public static void GuidToInt16(Guid guidToConvert, out long guidAsLong1, out long guidAsLong2)
{
byte[] guidByteArray = guidToConvert.ToByteArray();
var segment1 = new ArraySegment<byte>(guidByteArray, 0, 8);
var segment2 = new ArraySegment<byte>(guidByteArray, 8, 8);
guidAsLong1 = BitConverter.ToInt64(segment1.ToArray(), 0);
guidAsLong2 = BitConverter.ToInt64(segment2.ToArray(), 0);
}
public static Guid Int16ToGuid(long guidAsLong1, long guidAsLong2)
{
var segment1 = BitConverter.GetBytes(guidAsLong1);
var segment2 = BitConverter.GetBytes(guidAsLong2);
return new Guid(segment1.Concat(segment2).ToArray());
}
可能的用法:
Guid guidToConvert = new Guid("cbd5bb87-a249-49ac-8b06-87c124205b99");
long guidAsLong1, guidAsLong2;
GuidToInt16(guidToConvert, out guidAsLong1, out guidAsLong2);
Console.WriteLine(guidAsLong1 + " " + guidAsLong2);
Guid guidConvertedBack = Int16ToGuid(guidAsLong1, guidAsLong2);
Console.WriteLine(guidConvertedBack);
Console.ReadKey();
答案 2 :(得分:0)
我的解决方案应该有助于理解二进制操作的整个过程:
class Program
{
public static Guid LongsToGuid(long l1, long l2)
{
var a = (int)l1;
var b = (short)(l1 >> 32);
var c = (short)(l1 >> 48);
var d = (byte)l2;
var e = (byte)(l2 >> 8);
var f = (byte)(l2 >> 16);
var g = (byte)(l2 >> 24);
var h = (byte)(l2 >> 32);
var i = (byte)(l2 >> 40);
var j = (byte)(l2 >> 48);
var k = (byte)(l2 >> 56);
return new Guid(a, b, c, d, e, f, g, h, i, j, k);
}
public static long BytesToLong(byte[] bytes, int start, int end)
{
long toReturn = 0;
for (var i = start; i < end; i++)
{
toReturn |= ((long)bytes[i]) << (8 * i);
}
return toReturn;
}
static void Main(string[] args)
{
var l1 = long.MinValue;
var l2 = long.MaxValue;
var guid = LongsToGuid(l1, l2);
var guidBytes = guid.ToByteArray();
var readL1 = BytesToLong(guidBytes, 0, 8);
var readL2 = BytesToLong(guidBytes, 8, 16);
Console.WriteLine(l1 == readL1);
Console.WriteLine(l2 == readL2);
Console.ReadKey();
}
}
答案 3 :(得分:0)
作为unsafe
但非常有效的版本(没有byte[]
分配,通过BitConverter
):
static void Main()
{
var g = Guid.NewGuid();
Console.WriteLine(g);
GuidToInt64(g, out var x, out var y);
Console.WriteLine(x);
Console.WriteLine(y);
var g2 = GuidFromInt64(x, y);
Console.WriteLine(g2);
}
public static unsafe void GuidToInt64(Guid value, out long x, out long y)
{
long* ptr = (long*)&value;
x = *ptr++;
y = *ptr;
}
public static unsafe Guid GuidFromInt64(long x, long y)
{
long* ptr = stackalloc long[2];
ptr[0] = x;
ptr[1] = y;
return *(Guid*)ptr;
}
如果你不喜欢使用unsafe
关键字,你实际上可以用union结构做同样的事情,但是:它是更多的代码,而union结构仍然是根本无法验证的,所以这并不是'在IL级别获得很多(这只是意味着你不需要“允许不安全的代码”标志):
static void Main()
{
var g = Guid.NewGuid();
Console.WriteLine(g);
var val = new GuidInt64(g);
var x = val.X;
var y = val.Y;
Console.WriteLine(x);
Console.WriteLine(y);
var val2 = new GuidInt64(x, y);
var g2 = val2.Guid;
Console.WriteLine(g2);
}
[StructLayout(LayoutKind.Explicit)]
struct GuidInt64
{
[FieldOffset(0)]
private Guid _guid;
[FieldOffset(0)]
private long _x;
[FieldOffset(8)]
private long _y;
public Guid Guid => _guid;
public long X => _x;
public long Y => _y;
public GuidInt64(Guid guid)
{
_x = _y = 0; // to make the compiler happy
_guid = guid;
}
public GuidInt64(long x, long y)
{
_guid = Guid.Empty;// to make the compiler happy
_x = x;
_y = y;
}
}