Как конвертировать Long в Guid и наоборот? - PullRequest
5 голосов
/ 10 октября 2010

Возможно ли это вообще?Я даже не думаю, что это так, но я видел некоторый код, который пытался это сделать.Однако мои юнит-тесты показали, что он не работает.Я видел похожие мысли:

Просто для уточнения.Создание Guid находится вне моего контроля;поэтому я не могу просто сохранить значение в одном из наборов Guid.

Ответы [ 4 ]

15 голосов
/ 01 июля 2011

GUID никогда не может быть длинным, потому что, как я уже сказал, размер GUID составляет 16 байт, и размер long составляет 8 байт. Вы Cannoy счастливо сбросить 8 байтов от GUID, даже если они нули! : -)

Guid - это просто 128-битная структура данных, а long - это 64-битная структура данных ...

Это означает, что до тех пор, пока старшие 64 бита являются нулями, мы можем безопасно отбрасывать их и позже восстанавливать их, так как в этом случае нули не означают полные данные. Так что да, это потеря данных, но при определенных обстоятельствах это потеря данных, которые можно восстановить. (Думаю с точки зрения сжатия)

Это ничем не отличается от того, когда вы говорите:

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.

В качестве меры предосторожности я добавил исключение OverflowException в тех случаях, когда Guid на самом деле хранит что-либо, кроме 0, в последних 64 битах, так как результирующий длинный не сможет быть преобразован обратно в тот же Guid. *

Итак, как таковой ...

Пока созданный гид подходит чем долго, это возможно? Это только когда это проходит над указанный размер. Правильно?

Верно ... Очевидно, что соответствующее длинное значение GUID не легко читаемо, вот несколько примеров (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

И да, преобразование этих способов работает в обе стороны и для любой длинной ценности, которую вы можете придумать ...

Но потому что вы утверждаете, что:

Создание Guid находится вне моего контроля.

Крайне маловероятно, что вы на самом деле можете сделать это, вместо этого, скорее всего, ваш Guid сгенерирован с использованием любого из распространенных алгоритмов, и это сделает Guid непригодным для использования в этом сценарии.


Теперь, имеет ли это смысл делать? ... Это требует понимания конкретной ситуации, и это совсем другое обсуждение ...

9 голосов
/ 10 октября 2010

GUID имеет длину 16 байтов. «Длинный» часто понимается как длина в 64 бита (то есть 8 байтов). Вы не можете конвертировать между ними без потери или предоставления дополнительных данных.

1 голос
/ 16 мая 2018

Я знаю, что этот Вопрос действительно старый, но это первый результат Google, и я хотел бы дать ответ, с которым я собираюсь.

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

Может быть, это кому-то поможет!

0 голосов
/ 10 октября 2010

Вы можете использовать конструктор 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).Если вам нужно больше, чем это, вы должны использовать другой набор.

Каждый набор представляет собой шестнадцатеричное представление целого числа без знака, так что вы можете поиграть с возможностями.

...