IEnumerable.GroupBy is not grouped
I'm having trouble using the GroupBy extension in .NET (4.5, no matter VB.NET or C #. Exaples are in C #). Here's the situation:
2 example classes:
public class Office : IEquatable<Office>
{
public String Name { get; set; }
public int Id { get; set; }
public String Stuff { get; set; }
// Compare by values
public bool Equals(object obj)
{
if (obj is Office)
{
Office cmp = (Office) obj;
bool result = true;
result &= cmp.Id == this.Id;
result &= cmp.Name == this.Name;
result &= cmp.Stuff == this.Stuff;
return result;
}
else return false;
}
// Hashcode by values
public int GetHashCode()
{
var obj = new { Id = this.Id, Name = this.Name, Stuff = this.Stuff };
return obj.GetHashCode();
}
// IEquatable uses overriden Equals implementation
bool IEquatable<Office>.Equals(Office other)
{
return this.Equals(other);
}
}
public class Company
{
public Office Office { get; set; }
public String Name { get; set; }
}
Class Office overrides equality comparison functions and implements the IEquatable interface, in which case (as I understand it) the Default EqualityComparer uses my impementation of Equals.
Now I want to group the list of companies according to the offices they occupy, for example:
List<Company> companies = new List<Company>();
Office office1 = new Office();
office1.Id = 1;
office1.Name = "Office";
office1.Stuff = "Stuff";
Office office2 = new Office();
office2.Id = 1;
office2.Name = "Office";
office2.Stuff = "Stuff";
Company date1 = new Company();
date1.Office = office1;
date1.Name = "Date 1";
Company date2 = new Company();
date2.Office = office2;
date2.Name = "Date 2";
companies.Add(date1);
companies.Add(date2);
IEnumerable<IGrouping<Office, Company>> grouping = companies.GroupBy(x => x.Office);
Console.WriteLine("Groups: " + grouping.Count()); // returns 2!!!
Console.WriteLine("Equals: " + office1.Equals(office2)); // returns true
Console.WriteLine("Hash 1: " + office1.GetHashCode()); // returns 2067935290
Console.WriteLine("Hash 2: " + office2.GetHashCode()); // returns 2067935290
IEqualityComparer cmp = EqualityComparer<Office>.Default;
Console.WriteLine("Comparer: " + cmp.Equals(office1, office2)); // returns true
You can see that each company has a different Office object, but in my application logic, these objects are considered equal. Therefore, the call office1.Equals(office2)
returns true, the hash codes of the object are equal, and using the EqualityComparer<Office>.Default
function Equals
also returns true.
Now the conundrum is why the call to the GroupBy office returns two groups even though the offices are "equal". The documentation states that the default EqualComparer key parameter is used ( http://msdn.microsoft.com/en-us/library/vstudio/bb534501(v=vs.100).aspx ).
Thanks for the help ~
source to share
By default, the comparator calls Object.GetHashCode
and IEquatable<Office>.Equals
.
This doesn't work for you, because you are hiding the member GetHashCode()
, not overriding it.
Your methods Equals
and GetHashCode
should be changed:
public **override** bool Equals(object obj)
public **override** int GetHashCode()
source to share
Jan, you can set the modifier override
in inherited methods GetHashCode
and Equals
and then count the groups to 1. This is because when the companions are offices, the Equal
default calling method and calling method are Equal
contained in the class Office
. Correct, for example:
public class Office : IEquatable<Office>
{
public String Name { get; set; }
public int Id { get; set; }
public String Stuff { get; set; }
// Compare by values
public override bool Equals(object obj)
{
if (obj is Office)
{
Office cmp = (Office) obj;
bool result = true;
result &= cmp.Id == this.Id;
result &= cmp.Name == this.Name;
result &= cmp.Stuff == this.Stuff;
return result;
}
else return false;
}
// Hashcode by values
public override int GetHashCode()
{
var obj = new { Id = this.Id, Name = this.Name, Stuff = this.Stuff };
return obj.GetHashCode();
}
// IEquatable uses overriden Equals implementation
bool IEquatable<Office>.Equals(Office other)
{
return this.Equals(other);
}
}
source to share