【问题标题】:Convert Int to Guid将 Int 转换为 Guid
【发布时间】:2020-06-12 23:01:19
【问题描述】:

我必须将 Convert Int32 转换为 Guid,这就是我想出的。

public static class IntExtensions
{
    public static Guid ToGuid(this Int32 value)
    {
        if (value >= 0) // if value is positive
            return new Guid(string.Format("00000000-0000-0000-0000-00{0:0000000000}", value));
        else if (value > Int32.MinValue) // if value is negative
            return new Guid(string.Format("00000000-0000-0000-0000-01{0:0000000000}", Math.Abs(value)));
        else //if (value == Int32.MinValue)
            return new Guid("00000000-0000-0000-0000-012147483648");  // Because Abs(-12147483648) generates a stack overflow due to being > 12147483647 (Int32.Max)
    }
}

但它有点难看。有人有更好的主意吗?

更新:

是的,我知道整件事很丑陋,但我失去了想法。 问题是。我正在获取数据并且必须将其存储到我无法更改的表中。发送数据的主键是一个 Int,我必须存储它的表主键是一个 Guid。 问题是我必须了解发件人在谈论什么对象,但只能将其存储为 Guid。

更新 2:

好的,我知道我必须在这里提供更多信息。我是一个接收数据的 Web 服务,必须将数据传递给我也无法控制的接口。所以我既不能对接收到的数据进行建模,也不能对必须发送数据的(接口)数据库进行建模。此外,我必须以某种方式映射这两个东西,以便我可以以某种方式更新项目。 叹息

【问题讨论】:

  • 一个“INT”是 4 字节 - GUID 是 16 字节 - 这怎么可能远程工作!?!?!
  • 这会很丑。当您尝试将三轮车改装成摩托车时,就会发生这种情况。
  • 您需要告诉我们您的要求。你必须能够扭转这个过程吗?这些 ID 需要是全局唯一的还是本地唯一的?这是一个短期解决方案,还是这些 ID 会永远在您的数据库中使用? =)
  • 您没有创建 guid,它们无效。
  • 创建包含这两个键的映射表不是更可靠吗?

标签: c#


【解决方案1】:

这是一个简单的方法:

public static Guid ToGuid(int value)
{
    byte[] bytes = new byte[16];
    BitConverter.GetBytes(value).CopyTo(bytes, 0);
    return new Guid(bytes);
}

您可以更改复制发生的位置(将索引从 0 更改为 12)。这实际上取决于您要如何定义这种不寻常的“int 到 Guid”转换。

【讨论】:

  • 非常感谢西蒙,我一直在寻找像这样更干净的东西,尽管我必须考虑解决我的问题的选项。我缺乏太多的控制力,以至于我可能真的不得不这样做。再次感谢您。
【解决方案2】:

有同样的问题,需要一个 Int 到 Guid 然后回到 Int。使用 int ID 但处理功能需要 Guid 的旧数据。编写额外功能和数据库更改的代码要少得多。只是更容易以 Guid 形式传递 Int iD,因为它知道它不会将其用作最终的保存 Guid。保存是一个插入,所以它在最后得到了一个新的 Guid。

这是上面的代码和另一篇文章中关于 Guid 到 int 并让 Int 退出的想法。

public static Guid Int2Guid(int value)
{
    byte[] bytes = new byte[16];
    BitConverter.GetBytes(value).CopyTo(bytes, 0);
    return new Guid(bytes);
}

public static int Guid2Int(Guid value)
{
    byte[] b = value.ToByteArray();
    int bint = BitConverter.ToInt32(b, 0);
    return bint;
}

这个 Guid2Int 应该只传递一个来自 Int 的 Guid。

【讨论】:

  • 字符串版本:public static Guid String2Guid(string value) { byte[] bytes = new byte[16]; Encoding.ASCII.GetBytes(value).CopyTo(bytes, 0);返回新的指导(字节); } 公共静态字符串 Guid2String(Guid 值) { byte[] b = value.ToByteArray(); ASCIIEncoding 编码器 = new ASCIIEncoding();字符串 s = encoder.GetString(b).Trim('\0');返回 s; }
【解决方案3】:

您可以从 int 中获取数字并对其进行格式化,使它们看起来像 GUID,但这不会使结果成为 GUID。 GUID 基本上是一个 16 字节的数字,它是使用保证该数字唯一的算法计算的。您可以整天在世界上的每台计算机上生成 GUID 而不会得到重复(至少理论上是这样)。重新格式化的 int 不是唯一的,它绝对不是 GUID。

【讨论】:

  • +1,只剩下:en.wikipedia.org/wiki/Globally_unique_identifier,探索生成它们的各种奇妙算法。
  • 是的,但是,在 GUID 的规范中,有一种方法可以将经典标识符转换为 GUID。我在想一个保留字符。让我们说一下,当 GUID 以 0 开头时,你可以做你想要的,但你不能保证。所以所有以 0 开头的 GUID 意味着它们是手动生成的,没有算法。
【解决方案4】:

我也需要将数据库的主键(uint)编码为 GUID。关于是否使用单位作为主键或 Guid 有很多讨论,我不会在这里讨论,但我使用 uint 作为主键,使用 guid 作为列,我想将主键编码为guid,然后从 guid 中取回。

以下解决方案将 24 位主键(一个 uint)编码为 Guid,然后将其解码回来。它在 uint 上使用 DES 加密。我认识到这个问题需要一个 32 位 int,这适用于 24 位 uint,但是可以通过连接两个 GUID 来实现 32,一个是最高有效的 24 位,一个是最低有效的 24 位,总共得到 48 位。该算法经过全面测试,可用于 int,但未针对负数进行测试。

GUID 格式

GUID 格式是 32 位数字,可以用连字符分隔,并且包括大括号:00000000-0000-0000-0000-000000000000 (D),即 8-4-4-12 个字符,即 4-2-2- 6 个字节作为 1 个字节被编码为 2 个字符。存在其他格式的 GUID。

3 字节 uint 加密为 8 字节代码,从第 5 个字节开始写入 guid(这是 Guid 的第 10 个字符,忽略括号和“-”分隔符)。让 'z' 表示编码的 int,而 0 表示任何其他十六进制字符。结果编码的 GUID 是

00000000-zzzz-zzzz-zzzz-zzzz00000000

请注意,在此之后 GUID 可能不是全局唯一的。但是,鉴于 GUID 对您的主密钥进行编码,它对于您的主密钥将是唯一的,并且在没有加密密钥的情况下很难从 GUID 中提取 uint ......与 DES 加密一样安全。

public void Test()
{  
    Guid NewG = Guid.NewGuid();
    Guid EnryptedGuid = Utility.EncodeInt24InGUID(NewG, Num);
    uint RestoredUint = Utility.DecodeInt24FromGUID(EnryptedGuid);
}

加密

public static Guid EncodeInt24InGUID(Guid guid, uint x)
{
    if (x >= Math.Pow(2, 24))
            throw new ArgumentOutOfRangeException("Unsigned integer is greater than 24bit");

    string strGuid = guid.ToString();
    strGuid = Utility.RemoveChars(strGuid, "-{}");//Remove any '-' and '{}' characters
    byte[] bytes = BitConverter.GetBytes(x);
    var encryptedarray = Cypher.EncryptDES(bytes, Cypher.Key);
    string EncryptedGuid = WriteBytesToString(strGuid, encryptedarray, 9);
    Guid outg;
    Guid.TryParse(EncryptedGuid, out outg);
    return outg;
}

RemoveChars 从这里复制/改编 Removing characters from strings with LINQ

WriteBytesToString 如下

public static string WriteBytesToString(string Input, byte[] bytes, int start)
{
    StringBuilder g = new StringBuilder(Input);
    string temp;
    int ByteNum = 0;
    int CharPos = start;
    int NumBytes = (int)bytes.LongLength; 
    for (int i = 0; i < NumBytes; i++)
    {
        temp = string.Format("{0:x2}", bytes[ByteNum++]);
        g[CharPos++] = (temp.ToCharArray())[0];
        g[CharPos++] = (temp.ToCharArray())[1];
    }
    return g.ToString();
}

解密

public static uint DecodeInt24FromGUID(Guid guid)
{
    string strGuid = guid.ToString();
    strGuid = Utility.RemoveChars(strGuid, "-{}");
    byte[] EncryptedBytes = GetBytesFromString(strGuid, 9,8);
    var decrypted = Cypher.DecryptDES(EncryptedBytes, Cypher.Key);
    uint DecryptedUint = BitConverter.ToUInt32(decrypted, 0);
    return DecryptedUint;
}

GetBytesFromString。请注意,字节从第 9 个索引开始,并且在调用函数中硬编码为 8 个字节。请参阅有关 GUID 格式的说明

public static byte[] GetBytesFromString(string Input, int start, int NumBytes)
{
    StringBuilder g = new StringBuilder(Input);
    byte[] Bytes = new byte[NumBytes];
    string temp;
    int CharPos = start;
    for (int i = 0; i < NumBytes; i++)
    {
        temp = g[CharPos++].ToString();
        temp += g[CharPos++].ToString();
        Bytes[i] =  byte.Parse(temp, System.Globalization.NumberStyles.HexNumber);
    }
    return Bytes;
}

cyber类是从https://www.codeproject.com/Articles/5719/Simple-encrypting-and-decrypting-data-in-C这里复制过来的,并适配DES加密。全文贴在下面

using System.IO;
using System.Security.Cryptography;
namespace UtilityLib
{
    // This class is adapted from https://www.codeproject.com/Articles/5719/Simple-encrypting-and-decrypting-data-in-C
    public static class Cypher
    {
        public static string Key = "Asd9847Fg85ihkn52s";
        // Encrypt a byte array into a byte array using a key and an IV 
        public static byte[] EncryptDES(byte[] clearData, byte[] Key, byte[] IV)
        {
            // Create a MemoryStream to accept the encrypted bytes 
            MemoryStream ms = new MemoryStream();
            TripleDES alg = TripleDES.Create();
            alg.Key = Key;
            alg.IV = IV;
            CryptoStream cs = new CryptoStream(ms,alg.CreateEncryptor(), CryptoStreamMode.Write);
            cs.Write(clearData, 0, clearData.Length);
            cs.Close();
            byte[] encryptedData = ms.ToArray();
            return encryptedData;
        }

        public static byte[] EncryptDES(byte[] clearData, string Password)
        {
            PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
                new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d,
            0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
            return EncryptDES(clearData, pdb.GetBytes(24), pdb.GetBytes(8));
        }
        public static byte[] DecryptDES(byte[] cipherData, byte[] Key, byte[] IV)
        {
            MemoryStream ms = new MemoryStream();
            TripleDES alg = TripleDES.Create(); 
            alg.Key = Key;
            alg.IV = IV;
            CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
            cs.Write(cipherData, 0, cipherData.Length);
            cs.Close();
            byte[] decryptedData = ms.ToArray();
            return decryptedData;
        }

        public static byte[] DecryptDES(byte[] cipherData, string Password)
        {
            PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
                new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d,
            0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
            return DecryptDES(cipherData, pdb.GetBytes(24), pdb.GetBytes(8));
        }
    }
}

【讨论】:

    【解决方案5】:

    我会更进一步。

    有时需要想出一种在intGuid 之间来回切换的方法。添加两个甚至四个ints的复合id来混合。

    我想出了这个:

    [StructLayout(LayoutKind.Explicit, Size = 16)]
    public struct GuidToInt32 :
        IEquatable<GuidToInt32>
    {
        public static readonly GuidToInt32 Empty;
    
        [FieldOffset(0)]
        private readonly Guid guidValue;
    
        [FieldOffset(sizeof(int) * 0)]
        private readonly int int32Value1;
    
        [FieldOffset(sizeof(int) * 1)]
        private readonly int int32Value2;
    
        [FieldOffset(sizeof(int) * 2)]
        private readonly int int32Value3;
    
        [FieldOffset(sizeof(int) * 3)]
        private readonly int int32Value4;
    
        public GuidToInt32(Guid guidValue)
        {
            this.int32Value1 = default;
            this.int32Value2 = default;
            this.int32Value3 = default;
            this.int32Value4 = default;
    
            this.guidValue = guidValue;
        }
    
        public GuidToInt32(int int32Value1, int int32Value2 = default, int int32Value3 = default, int int32Value4 = default)
        {
            this.guidValue = default;
    
            this.int32Value1 = int32Value1;
            this.int32Value2 = int32Value2;
            this.int32Value3 = int32Value3;
            this.int32Value4 = int32Value4;
        }
    
        public Guid GuidValue => this.guidValue;
    
        public int Int32Value1 => this.int32Value1;
    
        public int Int32Value2 => this.int32Value2;
    
        public int Int32Value3 => this.int32Value3;
    
        public int Int32Value4 => this.int32Value4;
    
        public static bool operator ==(GuidToInt32 leftValue, GuidToInt32 rightValue)
        {
            return leftValue.guidValue == rightValue.guidValue;
        }
    
        public static bool operator !=(GuidToInt32 leftValue, GuidToInt32 rightValue)
        {
            return leftValue.guidValue != rightValue.guidValue;
        }
    
        public static bool Equals(GuidToInt32 valueA, GuidToInt32 valueB)
        {
            return valueA.guidValue == valueB.guidValue;
        }
    
        public bool Equals(GuidToInt32 other)
        {
            return this.guidValue == other.guidValue;
        }
    
        public override bool Equals(object obj)
        {
            if (obj is GuidToInt32 color)
            {
                return GuidToInt32.Equals(this, color);
            }
    
            return false;
        }
    
        public override int GetHashCode()
        {
            return this.guidValue.GetHashCode();
        }
    }
    

    这可以很容易地与其他类型一起使用,例如uintlongulongfloatdouble ...

    我不会在新建项目中使用它,但它非常适合可恢复的迁移过程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-23
      • 1970-01-01
      • 1970-01-01
      • 2019-06-18
      • 1970-01-01
      相关资源
      最近更新 更多