SumGuy SumGuy - 3 months ago 21
C# Question

Linq to Sql Group By Class

I would like to pass a groupedList to several functions, however I'm getting strange results when trying to group by using a class rather than an anonymous type. In the following example the anonymous type returns 2 results, as expected, but the concrete class returns 5, as if it wasn't even grouped.

The Question: Is it possible to do Linq to Sql Group By with concrete classes?

public class person
{
public string Name;
public string State;
}

public class personGroup
{
public string State;
public personGroup(string personState)
{
State = personState;
}
}


void Main()
{
var people = new List<person>();
people.Add(new person {Name = "Bob", State = "Tx"});
people.Add(new person {Name = "Bill", State = "Tx"});
people.Add(new person {Name = "Tracy", State = "Tx"});
people.Add(new person {Name = "Steve", State = "Md"});
people.Add(new person {Name = "Kelly", State = "Md"});

var groupedPeople = people.GroupBy (p => p.State );
groupedPeople.Count().Dump();//Returns 2

var morePeople = people.GroupBy (p => new personGroup(p.State) );
morePeople.Count().Dump();//Returns 5
}

Answer

The GroupBy method uses EqualityComparer<T>.Default to compare the items in question when a custom IEqualityComparer is not provided (you did not provided one). This will be based on the implementation of IEquatable<T> of the type T in question, if there is one, and if not, then it will simply use object.Equals and object.GetHashCode of that type.

Your custom type does not provide any implementation whatsoever, it relies entirely on the implementations defined in object, which, for a reference type, is based on the reference of the object. Each of the personGroup objects you created have a different reference, and so are different.

Anonymous types don't use that default equality behvaior; they override the definition of Equals and GetHashCode to be dependent on the identity of each of the properties they represent.

If you want to use your own custom type to group on, and the default equality semantics aren't what you want, you'll need to either provide a custom IEqualityComparer implementation, or override Equals and GetHashCode for the type in question.