C#无法向字典添加值,但该值尚不存在

时间:2018-10-11 10:23:32

标签: c# dictionary key equals

我创建了一个词典,并尝试添加一些值。这些值是我们生成的代码的输入属性:

_inputParameterMapping = new Dictionary<IVariable, IExpression>();

我必须添加三个值,但是字典给我以下错误:

  

“具有相同键的项目已被添加”

当我比较这些值时,它们并不相等。 (请参阅附件1和2)。在附件中,您会看到两个键的 memberNames 彼此不同。

enter image description here enter image description here

两个键的 HashCodes 彼此相等,但是对象不相等,并且Equals函数的结果为“ true”(请参阅​​附件3) enter image description here

这是我的功能:

public StoredProcedureCall(IStoredProcedureDeclaration storedProcedure, params IExpression[] inputValues)
{
    if (storedProcedure == null) 
        throw new ArgumentNullException("storedProcedure");

    if (inputValues.Length > storedProcedure.InputParameters.Length)
        throw new ArgumentException("inputValues length does not match function.InputParameters length");

    _storedProcedure = storedProcedure;
    _inputValues = inputValues;

    _inputParameterMapping = new Dictionary<IVariable, IExpression>();
    for (var i = 0; i < _inputValues.Length; i++)
    {
        if (!storedProcedure.InputParameters[i].ParameterType.IsInstanceOfType(_inputValues[i]))
        {
            throw new ArgumentException(string.Format("inputArgument {0} type ({1}) is not same as inputParameter '{2}' type ({3}) in stored procedure '{4}'",
                i,
                ReflectionUtils.GetTypeNameWithoutNameSpaceQualifiers(_inputValues[i].Type.GetType()),
                storedProcedure.InputParameters[i].Template.MemberName,
                ReflectionUtils.GetTypeNameWithoutNameSpaceQualifiers(storedProcedure.InputParameters[i].ParameterType),
                _storedProcedure.MemberName));
        }

        _inputParameterMapping.Add(storedProcedure.InputParameters[i].Template, _inputValues[i]);
    }
}

该问题怎么发生?为什么字典认为这些属性彼此相等?

谢谢你!

亲切的问候, 耶尔

2 个答案:

答案 0 :(得分:0)

  

两个键的HashCode彼此相等

这是问题所在,因为

  

Dictionary类被实现为哈希表。 -MSDN

,并使用GetHashCode函数作为默认的哈希算法。

解决方案1 ​​

为您的IVariable实现覆盖GetHashCode(和Equal),并向其添加MemberName:

override int GetHashCode()
{
    return base.GetHashCode() | MemberName.GetHashCode();
}

这是一个基本解决方案,将忽略IVariable接口的所有其他成员

解决方案2

  

如果类型TKey实现System.IEquatable通用接口,则默认的相等比较器将使用该实现

实现IEquatable界面

public bool Equals(IVariable other)
{
    if(this.MemberName!= other.MemberName)
         return false;

    //... Compare other members ...
}

答案 1 :(得分:0)

它表明您在对象比较方面存在问题。您的方向员真的不知道如何比较您的关键对象。我建议实现IEqualityComparer并将其用于字典。看一下我的样本:

    public static void DoStuff()
    {
        var one = new SomeClass(10);
        var two = new SomeClass(200);
        var three = new SomeClass(10); //same value as object "one"

        var myComparer = new SomeClassComparer();
        var myDictionary = new Dictionary<SomeClass, object>(myComparer);
        myDictionary.Add(one, "Some Data");
        myDictionary.Add(two, new[] { 1, 2, 3, 4 } );
        // causes exceptions even if InitializationTime differs because of SomeClass.ImportantValue comparison 
        myDictionary.Add( three, new List<object>() );
    }
    public class SomeClass
    {
        public int ImportantValue { get; set; }
        public DateTime InitializationTime { get; set; }
        public SomeClass(int value)
        {
            ImportantValue = value;
            //every object gets its "unique" InitializationTime
            InitializationTime = DateTime.Now;
        }
    }

    public class SomeClassComparer : IEqualityComparer<SomeClass>
    {
        public bool Equals(SomeClass x, SomeClass y)
        {
            //do comparison of data that represents the identity of the objects data
            return x.ImportantValue.Equals(y.ImportantValue);
        }
        public int GetHashCode(SomeClass obj)
        {
            //calculate a hash code from data that represents the identity of the objects data
            return (obj.ImportantValue).GetHashCode();
        }
    }