Общий словарь C # TryGetValue не находит ключи - PullRequest
11 голосов
/ 02 апреля 2012

У меня есть простой пример:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<MyKey, string> data = new Dictionary<MyKey, string>();
            data.Add(new MyKey("1", "A"), "value 1A");
            data.Add(new MyKey("2", "A"), "value 2A");
            data.Add(new MyKey("1", "Z"), "value 1Z");
            data.Add(new MyKey("3", "A"), "value 3A");

            string myValue;
            if (data.TryGetValue(new MyKey("1", "A"), out myValue))
                Console.WriteLine("I have found it: {0}", myValue );

        }
    }

    public struct MyKey
    {
        private string row;
        private string col;

        public string Row { get { return row; } set { row = value; } }
        public string Column { get { return col; } set { col = value; } }

        public MyKey(string r, string c)
        {
            row = r;
            col = c;
        }
    }
}

Это работает нормально. Но если я изменю структуру MyKey с помощью класса MyKey следующим образом:

public class MyKey

Тогда метод TryGetValue не находит ключ, несмотря на то, что ключ существует.

Я уверен, что упускаю что-то очевидное, но я не знаю, что.

Есть идеи?

Спасибо


** Решение **

(см. Принятое решение для лучшего разрешения GetHashCode)

Я переопределил класс MyKey следующим образом, и теперь все работает нормально:

public class MyKey
{
    private string row;
    private string col;

    public string Row { get { return row; } set { row = value; } }
    public string Column { get { return col; } set { col = value; } }

    public MyKey(string r, string c)
    {
        row = r;
        col = c;
    }

    public override bool Equals(object obj)
    {
        if (obj == null || !(obj is MyKey)) return false;

        return ((MyKey)obj).Row == this.Row && ((MyKey)obj).Column == this.Column;
    }

    public override int GetHashCode()
    {            
        return (this.Row + this.Column).GetHashCode();
    }    
}

Спасибо всем, кто ответил на это.

Ответы [ 3 ]

6 голосов
/ 02 апреля 2012

Вам необходимо переопределить Equals() и GetHashCode() в классе MyKey

Может быть, что-то вроде этого:

GetHashCode ()

public override int GetHashCode()
{
   return GetHashCodeInternal(Row.GetHashCode(),Column.GetHashCode());
}
//this function should be move so you can reuse it
private static int GetHashCodeInternal(int key1, int key2)
{
    unchecked
    {
        //Seed
        var num = 0x7e53a269;

        //Key 1
        num = (-1521134295 * num) + key1;
        num += (num << 10);
        num ^= (num >> 6);

        //Key 2
        num = ((-1521134295 * num) + key2);
        num += (num << 10);
        num ^= (num >> 6);

        return num;
    }
}

Равно

public override bool Equals(object obj)
{
    if (obj == null)
        return false;
    MyKey p = obj as MyKey;
    if (p == null)
        return false;

    // Return true if the fields match:
    return (Row == p.Row) && (Column == p.Column);
}
4 голосов
/ 02 апреля 2012

Поскольку классы сравниваются по умолчанию с использованием сравнения ссылок.

Если вы сравниваете два объекта, вы делаете объект.ReferenceEquals (obj1, obj2)

Если вы сравниваете две структуры, вы делаете сравнение значений (например, когда сравниваете две целые).

Если вы хотите сравнить два объекта MyKey, вам нужно реализовать собственный метод Equals и GetHashCode, и он будет автоматически использоваться в словаре.

3 голосов
/ 02 апреля 2012

Struct является типом значения, а Class является ссылочным типом, поэтому при использовании struct сравниваются все значения внутри него, но при использовании класса проверяется только ссылка на объект.

Вы можете изменить это поведение навернякаклассы путем переопределения Equals() метода.Вы также можете переопределить оператор ==, если хотите.См. Примеры в Рекомендации по перегрузке Equals () и оператора == (Руководство по программированию в C #) .

Редактировать:

Ваш метод Equals() должен выглядеть следующим образом:

public override bool Equals(System.Object obj)
    {
        MyKey p = obj as MyKey;
        if ((System.Object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (row == p.row) && (col == p.col);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...