HashCode on decimal with IEqualityComparer in a ConcurrentDictionary

这一生的挚爱 提交于 2020-02-08 06:53:09

问题


I made a class to be used as a key in a dictionary.

public class FourUintsOneDecimalKeyInfo
{
    public uint IdOne { get; set; }
    public uint IdTwo { get; set; }
    public uint IdThree { get; set; }
    public uint IdFour { get; set; }
    public decimal DefinitionOne { get; set; }

    public class EqualityComparerAssetTableInfo : IEqualityComparer<FourUintsOneDecimalKeyInfo>
    {
        public bool Equals(FourUintsOneDecimalKeyInfo x, FourUintsOneDecimalKeyInfo y)
        {
            return x.IdOne == y.IdOne &&
                    x.IdTwo == y.IdTwo &&
                    x.IdThree == y.IdThree &&
                    x.IdFour == y.IdFour &&
                    x.DefinitionOne == y.DefinitionOne;
        }

        public int GetHashCode(FourUintsOneDecimalKeyInfo x)
        {
            return (x.IdOne.ToString() +
                    x.IdTwo.ToString() +
                    x.IdThree.ToString() +
                    x.IdFour.ToString() +
                    x.DefinitionOne.ToString()).GetHashCode();
        }
    }
}

I use it like this:

ConcurrentDictionary<FourUintsOneDecimalKeyInfo,uint> _derivativeIds = new ConcurrentDictionary<FourUintsOneDecimalKeyInfo, uint>(new FourUintsOneDecimalKeyInfo.EqualityComparerAssetTableInfo());

but when I try to lookup a value, based on the key like:

uint theID;
bool gotId = theDict.TryGetValue(keyInfoInfo, out theID);

it always returns false (even when I'm sure the value I want to find is actually there. When I leave the public decimal DefinitionOne { get; set; } part out of the class and adjust the GetHashCode accordingly (like this)...

public class FourUintsKeyInfo
{
    public uint IdOne { get; set; }
    public uint IdTwo { get; set; }
    public uint IdThree { get; set; }
    public uint IdFour { get; set; }

    public class EqualityComparerAssetTableInfo : IEqualityComparer<FourUintsKeyInfo>
    {
        public bool Equals(FourUintsKeyInfo x, FourUintsKeyInfo y)
        {
            return  x.IdOne == y.IdOne && 
                    x.IdTwo == y.IdTwo && 
                    x.IdThree == y.IdThree && 
                    x.IdFour == y.IdFour;
        }

        public int GetHashCode(FourUintsKeyInfo x)
        {
            //todo: make a smarter / less cpu consuming algo
            return (x.IdOne.ToString() + x.IdTwo.ToString() + x.IdThree.ToString() + x.IdFour.ToString()).GetHashCode();
        }
    }

...it does work.

Any suggestions?

Kind regards,

Matthijs

This does work:

public int GetHashCode(FourUintsOneDecimalKeyInfo x)
        {
            //todo: make a smarter / less cpu consuming algo
            return (x.IdOne.ToString() +
                    x.IdTwo.ToString() +
                    x.IdThree.ToString() +
                    x.IdFour.ToString()).GetHashCode() +
                    x.DefinitionOne.GetHashCode();
        }

but it's probably not best practice...

for Jon:

strange thing...now it does work. Even with the old GetHasCode method.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Windows.Forms;

namespace ShowError

{ public partial class Form1 : Form {

    ConcurrentDictionary<FourUintsOneDecimalKeyInfo,uint> _dictWithIds = new ConcurrentDictionary<FourUintsOneDecimalKeyInfo, uint>(new FourUintsOneDecimalKeyInfo.EqualityComparerFourUintsOneDecimalKeyInfo());

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        FourUintsOneDecimalKeyInfo theKey = new FourUintsOneDecimalKeyInfo() { IdOne = 1, IdTwo = 1, IdThree = 1, IdFour = 1, DefinitionOne = 15.25M };

        _dictWithIds.TryAdd(theKey, 1);

        uint theID;
        bool GotTheID = _dictWithIds.TryGetValue(theKey, out theID);

        GotTheID = GotTheID; //returns true :-S
    }
}


public class FourUintsOneDecimalKeyInfo
{
    public uint IdOne { get; set; }
    public uint IdTwo { get; set; }
    public uint IdThree { get; set; }
    public uint IdFour { get; set; }
    public decimal DefinitionOne { get; set; }

    public class EqualityComparerFourUintsOneDecimalKeyInfo : IEqualityComparer<FourUintsOneDecimalKeyInfo>
    {
        public bool Equals(FourUintsOneDecimalKeyInfo x, FourUintsOneDecimalKeyInfo y)
        {
            return x.IdOne == y.IdOne &&
                    x.IdTwo == y.IdTwo &&
                    x.IdThree == y.IdThree &&
                    x.IdFour == y.IdFour &&
                    x.DefinitionOne == y.DefinitionOne;
        }

        public int GetHashCode(FourUintsOneDecimalKeyInfo x)
        {
            //todo: make a smarter / less cpu consuming algo
            return (x.IdOne.ToString() +
                    x.IdTwo.ToString() +
                    x.IdThree.ToString() +
                    x.IdFour.ToString() +
                    x.DefinitionOne.ToString()).GetHashCode();
        }
    }
}

}

Another extra edit: how it is filled.

it seems to go wrong, when I fill the dictionary from database info (MySQL). I fill it like this:

if(reader != null)
                    {
                        while(reader.Read())
                            theDict.TryAdd(new FourUintsOneDecimalKeyInfo
                            {
                                IdOne = (uint)reader[0],
                                IdTwo = (uint)reader[1],
                                IdThree = (uint)reader[2],
                                IdFour = (uint)reader[3],
                                DefinitionOne = (decimal)reader[4]
                            }, (uint)reader[5]);

                        reader.Close();
                    }

来源:https://stackoverflow.com/questions/17361088/hashcode-on-decimal-with-iequalitycomparer-in-a-concurrentdictionary

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!