Dictionary.ContainsKey возвращает False, но хочет True
namespace Dic
{
public class Key
{
string name;
public Key(string n) { name = n; }
}
class Program
{
static string Test()
{
Key a = new Key("A");
Key b = new Key("A");
System.Collections.Generic.Dictionary<Key, int> d = new System.Collections.Generic.Dictionary<Key, int>();
d.Add(a, 1);
return d.ContainsKey(b).ToString();
}
static void Main(string[] args)
{
System.Console.WriteLine(Test());
}
}
}
Что я должен изменить, чтобы получить правду?
Ответы
Ответ 1
Вы хотите true - но a и b - разные объекты.
Вам нужно переопределить GetHashCode и Equals в ключе Key
public class Key
{
string name;
public Key(string n) { name = n; }
public override int GetHashCode()
{
if (name == null) return 0;
return name.GetHashCode();
}
public override bool Equals(object obj)
{
Key other = obj as key;
return other != null && other.name == this.name;
}
}
Ответ 2
Вероятно, это поможет, если вы переопределите Key.GetHashCode и Key.Equals.
В Key
:
public override bool Equals(object obj)
{
var k = obj as Key;
if (k != null)
{
return this.name == k.name;
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return this.name.GetHashCode();
}
Ответ 3
Если у вас нет возможности переопределить операторы равенства /Equals/GetHashCode, как упомянули другие (например, вы не контролируете исходный код объекта), вы можете предоставить реализацию IEqualityComparer<Key>
в конструкторе словарь для выполнения проверок равенства.
class KeyComparer : IEqualityComparer<Key>
{
public bool Equals(Key x, Key y)
{
return x.Name == y.Name;
}
public int GetHashCode(Key obj)
{
return obj.Name.GetHashCode();
}
}
В своем роде ваш Ключ является ссылочным объектом, поэтому равенство определяется только по ссылке, если вы не сообщите миру (или словарю) в противном случае.
Ответ 4
Переопределение методов класса GetHashCode и Equals, чтобы он корректно работал в словаре, не очень хороший подход. То, как ведет себя словарь, должно быть детальностью реализации словаря, а не тем, какой класс используется в качестве ключа. У вас возникнут проблемы, если вы захотите использовать класс в разных словарях с различным поведением. Или если у вас нет доступа к исходному коду класса.
Лучшей ловушкой для мыши является предоставление словарю своего собственного компаратора. Например:
using System;
using System.Collections.Generic;
class Program {
static void Main(string[] args) {
var d = new Dictionary<Key, int>(new MyComparer());
d.Add(new Key("A"), 1);
Console.WriteLine(d.ContainsKey(new Key("a")));
Console.ReadLine();
}
private class MyComparer : IEqualityComparer<Key> {
public bool Equals(Key x, Key y) {
return string.Compare(x.Name, y.Name, true) == 0;
}
public int GetHashCode(Key obj) {
return obj.Name.ToUpper().GetHashCode();
}
}
public class Key {
public string Name { get; set; }
public Key(string name) { Name = name; }
}
}
Ответ 5
Чтобы использовать ваши собственные классы в качестве словарных ключей, вы должны переопределить GetHashCode и Equals. В противном случае он будет использовать адрес памяти для проверки равенства.
public class Key
{
string name;
public Key(string n) { name = n; }
public override int GetHashCode()
{
return name.GetHashCode();
}
public override bool Equals(object obj)
{
var other = obj as Key;
if( other == null )
return false;
return name == other.name;
}
}
Ответ 6
проблема заключается в том, что
new Key("A").Equals(new Key("A"))==false.
и
new Key("A").GetHashCode()!=new Key("A").GetHashCode()
исправить это, и он должен работать, я думаю. Чтобы исправить это, переопределите метод Equals и проверьте, совпадают ли значения имени. Вы также должны переопределить GetHashCode, если вы переопределяете Equals.
Ответ 7
вам нужно переопределить методы Equals и GetHashCode вашего класса Key.
Ответ 8
они имеют одинаковые значения внутри, но a!= b, поскольку они являются двумя разными переменными.
Ответ 9
Вам необходимо переопределить методы Equals
и GetHashCode
вашего класса Key. В вашем случае вы можете сравнить на основе имени ключа (или любого другого уникального свойства, если ваш класс более сложный).
public class Key {
string name;
public Key(string n) { name = n; }
public override bool Equals(object obj) {
Key k = obj as Key;
if (k == null)
return false;
return name.Equals(k.name);
}
public override int GetHashCode() {
return name.GetHashCode();
}
}
Ответ 10
1. Переопределить Equals, Get Hash Code и оператор '=='.
Класс Key должен переопределять Equals
, чтобы Словарь обнаруживал, являются ли они одинаковыми. Реализация по умолчанию будет проверять только ссылки.
Здесь:
public bool Equals(Key other)
{
return this == other;
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is Key))
{
return false;
}
return this.Equals((Key)obj);
}
public static bool operator ==(Key k1, Key k2)
{
if (object.ReferenceEquals(k1, k2))
{
return true;
}
if ((object)k1 == null || (object)k2 == null)
{
return false;
}
return k1.name == k2.name;
}
public static bool operator !=(Key k1, Key k2)
{
if (object.ReferenceEquals(k1, k2))
{
return false;
}
if ((object)k1 == null || (object)k2 == null)
{
return true;
}
return k1.name != k2.name;
}
public override int GetHashCode()
{
return this.name == null ? 0 : this.name.GetHashCode();
}
2. Если возможно, используйте struct.
Вы должны использовать структуру для неизменяемых типов данных, например, так как они передаются по значению. Это означало бы, что вы случайно не ввели два разных значения в один и тот же ключ.
Ответ 11
Затем вам нужно будет переопределить GetHashCode и Equals в классе Key.
Без этого вы получаете стандартную реализацию обоих. Какие результаты в hashcode для a и b, скорее всего, не совпадают (я не знаю, как выглядит реализация по умолчанию), а a определенно не равно b (реализация Equals() по умолчанию проверяет ссылочное равенство).
В вашем случае, если "имя" не является нулевым, оно может быть реализовано как
public class Key
{
string name;
public override int GetHashCode()
{
return name.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
Key objAsKey = obj as Key;
if (objAsKey == null)
{
return false;
}
return this.name.Equals(objAsKey.Name);
}
}
Является ли это удовлетворительным хешем, это другая история, но тем не менее она показывает принцип.
Ответ 12
ContainsKey в этом случае сравнивает Key как объекты и проверяет, являются ли сами объекты одинаковыми - они не являются. Вам необходимо реализовать IComparable или переопределить Key.Equals или что-то в этом направлении, чтобы заставить его делать то, что вы хотите.