基于MyModel模型实现多索引动态分组:如何通过循环动态创建GroupBy分组键?
Great question! Your current hardcoded anonymous type approach works fine for a fixed number of primary key columns, but it falls apart when the number of PK indexes changes (e.g., 1, 3, or more columns). Here's how you can dynamically create grouping keys that adapt to any length of pkColumnIndexes:
The Core Problem
Anonymous types and fixed-length tuples are compiled-time constructs—you can't dynamically add properties/elements to them at runtime. Instead, we need a grouping key that can handle variable-length data, plus a way to compare these keys correctly (since default equality checks for arrays use reference comparison, not content comparison).
Solution: Use an Array as the Grouping Key + Custom Equality Comparer
Here's a step-by-step implementation:
1. Create a Custom Equality Comparer for Arrays
This comparer will check if two arrays have identical content (which is what we need for grouping):
public class ArrayEqualityComparer : IEqualityComparer<object[]> { public bool Equals(object[] x, object[] y) { // Handle null cases if (x == null && y == null) return true; if (x == null || y == null) return false; // Different lengths can't be equal if (x.Length != y.Length) return false; // Compare each element in the array for (int i = 0; i < x.Length; i++) { if (!object.Equals(x[i], y[i])) return false; } return true; } public int GetHashCode(object[] obj) { if (obj == null) return 0; // Generate a hash code based on all elements in the array int hash = 17; foreach (var item in obj) { hash = hash * 31 + (item?.GetHashCode() ?? 0); } return hash; } }
2. Dynamically Generate Grouping Keys
Instead of hardcoding properties, extract the values from each row using the PK indexes and turn them into an array. Pass the custom comparer to GroupBy so it uses content-based equality:
// Get your dynamic PK indexes var pkColumnIndexes = GetPkIndexes(requestObject.columns); // Group rows using the dynamic PK values as the key var groupData = requestObject.rows .GroupBy( row => pkColumnIndexes.Select(idx => row[idx]).ToArray(), new ArrayEqualityComparer() ) .Select(group => group.LastOrDefault()) .ToList();
How It Works
- For each row, we select the values at the PK indexes and package them into an
object[]—this is our dynamic grouping key. - The
ArrayEqualityComparertellsGroupByto consider two arrays equal if all their elements are equal (instead of just comparing references). - This approach works for any number of PK indexes—1, 2, 5, or more.
Notes
- Make sure the data types in your rows implement
Equals()andGetHashCode()correctly (most built-in types likestring,intdo this by default). - If you want to avoid creating a custom comparer, you could serialize the PK values to a string (e.g., using JSON) as the grouping key, but this is less performant than using an array with a custom comparer.
内容的提问来源于stack exchange,提问作者anıl yıldırım

