Ключевые сравнения для Linq GroupBy с использованием стандартного EqualityComparer
Я пытаюсь сделать Linq GroupBy для некоторых объектов, используя явный тип ключа. Я не передаю IEqualityComparer
в GroupBy, поэтому согласно документам:
Сравнение сравнения по умолчанию Default
используется для сравнения ключей.
Он объясняет свойство EqualityComparer<T>.Default
следующим образом:
Свойство Default
проверяет, тип T
реализует System.IEquatable<T>
общий интерфейс и если это возвращает EqualityComparer<T>
, который использует это реализация.
В приведенном ниже коде я группирую массив из объектов Fred
. Они имеют ключевой тип, называемый FredKey
, который реализует IEquatable<FredKey>
.
Этого должно быть достаточно, чтобы сгруппировать работу, но группировка не работает. В последней строке ниже у меня должно быть 2 группы, но у меня нет, у меня всего 3 группы, содержащие 3 элемента ввода.
Почему группа не работает?
class Fred
{
public string A;
public string B;
public FredKey Key
{
get { return new FredKey() { A = this.A }; }
}
}
class FredKey : IEquatable<FredKey>
{
public string A;
public bool Equals(FredKey other)
{
return A == other.A;
}
}
class Program
{
static void Main(string[] args)
{
var f = new Fred[]
{
new Fred {A = "hello", B = "frog"},
new Fred {A = "jim", B = "jog"},
new Fred {A = "hello", B = "bog"},
};
var groups = f.GroupBy(x => x.Key);
Debug.Assert(groups.Count() == 2); // <--- fails
}
}
Ответы
Ответ 1
От MSDN
Если вы реализуете IEquatable, вы также должны переопределить реализации базового класса Object:: Equals (Object) и GetHashCode(), чтобы их поведение соответствовало их методу метода IEquatable:: Equals. Если вы переопределите Object:: Equals (Object), ваша переопределенная реализация также вызывается при вызове метода статического метода Equals (System.Object, System.Object) в вашем классе. Это гарантирует, что все вызовы метода Equals() возвращают согласованные результаты.
добавьте это в FredKey, и он должен работать
public override int GetHashCode()
{
return A.GetHashCode();
}
Ответ 2
Вот полный пример с помощью скрипта. Примечание: пример немного отличается от примера вопроса.
Следующая реализация IEquatable
может действовать как TKey
в GroupBy
. Обратите внимание, что он включает в себя как GetHashCode
, так и Equals
.
public class CustomKey : IEquatable<CustomKey>
{
public string A { get; set; }
public string B { get; set; }
public bool Equals(CustomKey other)
{
return other.A == A && other.B == B;
}
public override int GetHashCode()
{
return string.Format("{0}{1}", A, B).GetHashCode();
}
}
public class Custom
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
public static void Main()
{
var c = new Custom[]
{
new Custom {A = "hello", B = "frog" },
new Custom {A = "jim", B = "jog" },
new Custom {A = "hello", B = "frog" },
};
var groups = c.GroupBy(x => new CustomKey { A = x.A, B = x.B } );
Console.WriteLine(groups.Count() == 2);
}