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
}
The Linq GroupBy in C# belongs to the Grouping Operators category and exactly does the same thing as the Group By clause does in SQL Query. This method takes a flat sequence of elements and then organizes the elements into groups (i.e. IGrouping<TKey, TSource>) based on a given key.
The working of the GroupBy operator is similar to the SQL GroupBy clause. It is used to return the group of elements which share the common attributes or key from the given sequence or collection. Every group is represented by IGrouping<TKey, TElement> object.
GroupBy() Method in C# The GroupBy() is an extension method that returns a group of elements from the given collection based on some key value. arr. GroupBy(b => chkSmaller(b)); The above chkSmaller() finds the elements smaller than 50.
The GROUP BY statement groups rows that have the same values into summary rows, like "find the number of customers in each country". The GROUP BY statement is often used with aggregate functions ( COUNT() , MAX() , MIN() , SUM() , AVG() ) to group the result-set by one or more columns.
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.
In your second group by, there are 5 groups because the key is always different. personGroups
are compared by reference, and all of the objects have different references.You need to override Equals
and GetHashCode
methods in your personGroup
class to compare your instances based on State, or implement an IEqualityComparer<personGroup>
and pass it to GroupBy
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With