How to Convert Long to Guid and Vice Versa?
Asked Answered
M

7

9

Is this even possible? I don't even think it is, but I saw some code that was trying to do it. However, my unit tests showed that it was not working. I did see some similar thoughts:

Just for clarification. The Guid creation is outside of my control; therefore, I can't just store the value in one of the Guid sets.

Monochloride answered 10/10, 2010 at 14:30 Comment(0)
D
9

A GUID is 16 bytes long. A "long" is often understood as being 64 bits (i.e. 8 bytes) long. You cannot convert between those without losing or providing extra data.

Danit answered 10/10, 2010 at 14:37 Comment(4)
As long as the guid created fits in the the long, it is possible? It's just when it goes over the long's specified size. Correct?Monochloride
A GUID can never fit a long, because, as I say, a GUID's size is 16 bytes, and a long's size is 8 bytes. You cannoy happily discard 8 bytes off a GUID, even if they are zeroes! :-)Danit
You are absolutely correct. I wasn't thinking with that comment :)Monochloride
You are correct. Two notes: ulong in c# and "long long int" in c are exactly 64 bits, therefore a Guid fits ?just? in two of thoseSkirl
V
30

A GUID can never fit a long, because, as I say, a GUID's size is 16 bytes, and a long's size is 8 bytes. You cannoy happily discard 8 bytes off a GUID, even if they are zeroes! :-)

A Guid is merely a 128 bit data structure and a long is a 64 bit data structure...

That means that for as long as the upper 64 bits are Zeroes, we can safely discard them an at a later time reconstruct them as Zeroes are not meaning full data in this case. So yes it is loss of data, but under circumstances it is loss of data that can be reconstructed. (Think in terms of compression)

This is no different that when you say do:

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;

These explicit conversions are not built into the system as it is not so one must do it differently.

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);
}

Obviously this should never be used with GUID's in genneral, but is safe to use for as long as the GUID only has 64 bits of "actual data", best way to ensure that is to never use it on guids unless they where created using a long.

As a precaution I have added the throwing of an OverflowException in cases where the Guid actually stores anything but 0'es in the last 64 bits as the resulting long would not be able to be converted back to the same Guid.

So as such...

As long as the guid created fits in the the long, it is possible? It's just when it goes over the long's specified size. Correct?

Is true... Obviously the corresponding long value of the GUID is not easy readable, here are some examples (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

And yes conversion of those works both ways and for any long value you can think off...

But because you state that:

The Guid creation is outside of my control.

It is extremely unlikely that you can actually do this, instead it is most likely that the Guid you have is generated with any of the common algorithms, and that will make the Guid unusable in this scenario.


Now does this make any sense to do?... That requires an insight to a specific situation, and is a whole other discussion...

Vermiform answered 30/6, 2011 at 21:53 Comment(1)
Gosh, why is this answer not the accepted one. It's so thorough.Schnur
D
9

A GUID is 16 bytes long. A "long" is often understood as being 64 bits (i.e. 8 bytes) long. You cannot convert between those without losing or providing extra data.

Danit answered 10/10, 2010 at 14:37 Comment(4)
As long as the guid created fits in the the long, it is possible? It's just when it goes over the long's specified size. Correct?Monochloride
A GUID can never fit a long, because, as I say, a GUID's size is 16 bytes, and a long's size is 8 bytes. You cannoy happily discard 8 bytes off a GUID, even if they are zeroes! :-)Danit
You are absolutely correct. I wasn't thinking with that comment :)Monochloride
You are correct. Two notes: ulong in c# and "long long int" in c are exactly 64 bits, therefore a Guid fits ?just? in two of thoseSkirl
G
4

I know this Question is really old, but its the First Google Result, and i wanted to provide the answer im going with.

Guid isnt a Int64 as the others already stated, instead its two UInt64's.

I Wrote a UInt128 Class, with a High, and a Low UInt64. From there you need to just convert between those:

    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);
    }

Maybe it helps someone!

Goidelic answered 16/5, 2018 at 17:52 Comment(2)
Very useful, thanks. And I implemented with a hiLong and loLong because I had this need too; public members now are hiUlong, loUlong and the Long counterparts.Eucharis
This is a useful approach. Thank you for sharing.Cerelia
A
0

You can using Guid constructor, a simple but not flawless example:

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);

The first set can handle up to 4294967295 (int). If you need more than it then you have to use another set.

Each set is a hex representation of a unsigned integer, so you can play around with the possibilities.

Azzieb answered 10/10, 2010 at 14:52 Comment(0)
I
0
public static Guid ToGuid(long value)
{
    byte[] bytes = new byte[16];
    BitConverter.GetBytes(value).CopyTo(bytes, 0);
    return new Guid(bytes);
}

Hope, this code helps you!!!

Infinitude answered 9/8, 2019 at 13:23 Comment(0)
C
0

As long as you have to operate with positive integer values that not exceed Guid size, you can convert number to Guid like this:

var guid = new Guid(ulong.MaxValue.ToString("00000000-0000-0000-0000-000000000000"));

and convert it back like:

var uint64 = Convert.ToUInt64(guid.ToString("N"))

In other cases it is better to use bytes-conversion as mentioned above. Examples can be checked here: https://dotnetfiddle.net/Zx7faI

Congregate answered 13/3, 2021 at 15:10 Comment(0)
R
0

What you can do is map a long (64 bit) to a GUID (128 bit).
What you can't do is map a GUID (128 bit) to a long (64 bit).
What you actually want is mapping a GUID to a uint128 (or a int128).
Of course, mapping a long to a GUID requires a fillup of the upper part of uint128 with a zero.

What you need to consider is the special sort order of a GUID by its bytes (precendence of each byte), so that you can range-compare your GUIDs like you can with a long (long = int64).

For that you have to look at this answer:
SQL Server GUID sort algorithm

For how to map a long to a ulong, and a int to a uint, see:
Mapping a ulong to a long in C#?

For how to convert a UInt128 to a GUID, see ToGuidBytes() and ToGuid() in UInt128.cs on github and for converting a long into a UInt128, see the constructor of 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());
}

For System.Guid.NewGuid() see "NextUInt128":

And some tests to proof/check this works: BigIntUidTests.cs

Caveat emptor:
I don't know how a little vs. big endian machine will influence the result.

Rete answered 28/9, 2022 at 13:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.