Сравнение объекта, используемого в качестве ключа в словаре
мой класс:
public class myClass
{
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
public int D { get; set; }
}
и основной пример:
Dictionary<myClass, List<string>> dict = new Dictionary<myClass, List<string>>();
myClass first = new myClass();
first.A = 2;
first.B = 3;
myClass second = new myClass();
second.A = 2;
second.B = 3;
second.C = 5;
second.D = 6;
dict.Add(first, new List<string>());
if (dict.ContainsKey(second))
{
//
//should come here and update List<string> for first (and only in this example) key
//
}
else
{
//
//if myFirst object has difference vlues of A or B properties
//
dict.Add(second, new List<string>());
}
Как это сделать?
Ответы
Ответ 1
Если вы всегда хотите, чтобы словарь сравнивался только на A и B, у вас есть два варианта. Либо используйте конструктор, который реализует IEqualityComparer<TKey>
, и поместил туда свою логику сравнения или выполнил свой класс IEquateable<T>
GetHashCode и Equals, чтобы сопоставитель по умолчанию предоставил вам результаты, которые вы ищете.
Если вы хотите сравнить только A и B в одной ситуации, вам нужно будет использовать пропорцию .Keys и метод расширения Linq Содержит, который позволяет вам пройти через IEqualityComparer<T>
. Однако, делая это таким образом, вы теряете преимущества использования словаря, поэтому используйте его экономно.
public class MyClassSpecialComparer : IEqualityComparer<myClass>
{
public bool Equals (myClass x, myClass y)
{
return x.A == y.A && x.B == y.B
}
public int GetHashCode(myClass x)
{
return x.A.GetHashCode() + x.B.GetHashCode();
}
}
//Special case for when you only want it to compare this one time
//NOTE: This will be much slower than a normal lookup.
var myClassSpecialComparer = new MyClassSpecialComparer();
Dictionary<myClass, List<string>> dict = new Dictionary<myClass, List<string>>();
//(Snip)
if (dict.Keys.Contains(second, myClassSpecialComparer ))
{
//
//should come here and update List<string> for first (and only in this example) key
//
}
//If you want it to always compare
Dictionary<myClass, List<string>> dict = new Dictionary<myClass, List<string>>(new MyClassSpecialComparer());
Ответ 2
Переопределите в myClass:
-
Метод GetHashCode
-
Метод равенства
Для реализации метода GetHashCode вы можете просто XOR GetHashCodes из ваших целых свойств.
Опционально переопределить метод ToString и реализовать интерфейс IEquatable
Ответ 3
По умолчанию сравнение помещает объекты в ведра на основе их хеш-кода. Затем выполняется детальное сравнение (вызывая Equals
), если два хеш-кода являются одинаковыми. Если ваш класс не предоставляет GetHashCode
или реализует равенство, будет использоваться значение по умолчанию object.GetHashCode
, и в этом случае для семантики сравнения значений не будет использоваться ничего конкретного для вашего класса. Будет найдена только одна и та же ссылка. Если вы этого не хотите, выполните GetHashCode
и выполните равенство.
Например:
public class myClass
{
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
public int D { get; set; }
public bool Equals(myClass other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return other.A == A && other.B == B && other.C == C && other.D == D;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != typeof (myClass)) return false;
return Equals((myClass) obj);
}
public override int GetHashCode()
{
unchecked
{
int result = A;
result = (result*397) ^ B;
result = (result*397) ^ C;
result = (result*397) ^ D;
return result;
}
}
}