Converting System.Decimal to System.Guid

前端 未结 4 1232
南笙
南笙 2020-12-06 11:35

I have a big dictionary where the key is decimal, but the GetHashCode() of System.Decimal is disasterously bad. To prove my guess, I ran a for loop with 100.000 neigboring d

相关标签:
4条回答
  • 2020-12-06 12:09

    EXTREMELY HACKY SOLUTION (but probably fastest possible)

    public static class Utils
    {
        [StructLayout(LayoutKind.Explicit)]
        struct DecimalGuidConverter
        {
            [FieldOffset(0)]
            public decimal Decimal;
            [FieldOffset(0)]
            public Guid Guid;
        }
    
        private static DecimalGuidConverter _converter;
        public static Guid DecimalToGuid(decimal dec)
        {
            _converter.Decimal = dec;
            return _converter.Guid;
        }
        public static decimal GuidToDecimal(Guid guid)
        {
            _converter.Guid = guid;
            return _converter.Decimal;
        }
    }
    

    // Prints 000e0000-0000-0000-8324-6ae7b91d0100
    Console.WriteLine(Utils.DecimalToGuid((decimal) Math.PI));
    
    // Prints 00000000-0000-0000-1821-000000000000
    Console.WriteLine(Utils.DecimalToGuid(8472m));
    
    // Prints 8472
    Console.WriteLine(Utils.GuidToDecimal(Guid.Parse("00000000-0000-0000-1821-000000000000")));
    
    0 讨论(0)
  • 2020-12-06 12:26

    The distribution of GUID is good as it is meant to be unique...

    What is the range of numbers used for this? The default GetHashcode() implementation for Decimal might only take a certain range of values into consideration.

    0 讨论(0)
  • 2020-12-06 12:32

    If you're just trying to get a different hash algorithm, there's no need to convert to a Guid. Something like this:

    public int GetDecimalHashCode(decimal value)
    {
        int[] bits = decimal.GetBits(value);
        int hash = 17;
        foreach (int x in bits)
        {
            hash = hash * 31 + x;
        }
        return hash;
    }
    

    (Obviously substitute a different algorithm if you want.)

    Admittedly this still involves creating an array, which isn't ideal. If you really want to create a Guid you could use the code above to get the bits and then a long Guid constructor passing in appropriate values from the array.

    I'm somewhat suspicious of the decimal hashcode being so bad though. Do you have some sample code for that?

    0 讨论(0)
  • 2020-12-06 12:33

    Convert your decimal value to byte array, and then create a guid from it:

    public static byte[] DecimalToByteArray (decimal src) 
    {
        using (MemoryStream stream = new MemoryStream()) 
        {
            using (BinaryWriter writer = new BinaryWriter(stream))
            {
                writer.Write(src);
                return stream.ToArray();
            }
        }
    }
    
    Decimal myDecimal = 1234.5678M;
    Guid guid = new Guid(DecimalToByteArray(myDecimal));
    
    0 讨论(0)
提交回复
热议问题