C # не может добавить значение в словарь, но значение уже не существует - PullRequest
0 голосов
/ 11 октября 2018

Я создал словарь и пытаюсь добавить некоторые значения.Эти значения являются входными свойствами нашего сгенерированного кода:

_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 голосов
/ 11 октября 2018

Это говорит о том, что у вас возникла проблема со сравнением объектов.Ваш директор не знает, как сравнивать ключевые объекты.Я бы порекомендовал реализовать 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();
        }
    }
0 голосов
/ 11 октября 2018

Хэш-коды обоих ключей равны друг другу

, что является проблемой, поскольку

Класс словаря реализован в виде хеш-таблицы.- MSDN

и использует функцию GetHashCode в качестве алгоритма хеширования по умолчанию.

Решение 1

Переопределите GetHashCode (и равно) для вашей реализации IVariable и добавьте в него MemberNameto:

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 ...
}
...