所以我在SO和其他地方看了大约20个例子,但是没有找到一个涵盖我想要做的事情。这个 - Can I specify my explicit type comparator inline? - 看起来像我需要的东西,但是还不够(或者我不明白如何进一步了解。)
需要(我认为)提供自定义IEqualityComparer来指定如何比较GroupBy字段,但它们是匿名类型
private class LoadData
{
public PeriodEndDto PeriodEnd { get; set; }
public ComponentDto Component { get; set; }
public string GroupCode { get; set; }
public string PortfolioCode { get; set; }
}
我到目前为止最好的GroupBy查询:
var distinctLoads = list.GroupBy(
dl => new { PeriodEnd = dl.PeriodEnd,
Component = dl.Component,
GroupCode = dl.GroupCode },
(key, data) => new {PeriodEnd = key.PeriodEnd,
Component = key.Component,
GroupCode = key.GroupCode,
PortfolioList = data.Select(d=>d.PortfolioCode)
.Aggregate((g1, g2) => g1 + "," + g2)},
null);
这个组,但仍然有重复。
答案 0 :(得分:8)
这里的问题是您的密钥类型是匿名的,这意味着您无法声明为该密钥类型实现IEqualityComparer<T>
的类。虽然可能可能编写一个比较器,它以自定义方式比较匿名类型的相等性(通过泛型方法,委托和类型推断),但它不会非常令人愉快。
两个最简单的选项可能是:
PeriodEndDto
和ComponentDto
中的Equals / GetHashCode,使匿名类型“正常工作”。如果你想要在任何地方使用自然平等,这可能是最安全的选择。我建议同时实施IEquatable<T>
GetHashCode
和Equals
,或者您可以按正常方式编写自定义相等比较器编辑:ProjectionEqualityComparer
不会真的有用。写一些类似的东西是可行的 - 一种CompositeEqualityComparer
允许你从几个“投影+比较器”对创建一个相等比较器。与匿名类型相比,它会非常难看。
答案 1 :(得分:2)
编辑:
正如Jon Skeet所指出的,如果你不太考虑它,这个解决方案似乎比它更好,因为我忘记了实现GetHashCode。正如乔恩在答案中所说,必须实施GetHashCode才能实现这种方法,“不是非常令人愉快。”据推测,这也是对框架中EqualityComparer<T>.Create()
缺席(所谓的“莫名其妙”)的解释。我将留下答案供参考,作为不该做的例子,也可以是有益的。
原始回答:
您可以使用.NET 4.5中引入的Comparer<T>.Create
模式建议的方法(但在EqualityComparer<T>
中莫名其妙地缺席)。为此,请创建一个DelegateEqualityComparer<T>
类:
class DelegateEqualityComparer<T> : EqualityComparer<T>
{
private readonly Func<T, T, bool> _equalityComparison;
private DelegateEqualityComparer(Func<T, T, bool> equalityComparison)
{
if (equalityComparison == null)
throw new ArgumentNullException("equalityComparison");
_equalityComparison = equalityComparison;
}
public override bool Equals(T x, T y)
{
return _equalityComparison(x, y);
}
public static DelegateEqualityComparer<T> Create(
Func<T, T, bool> equalityComparison)
{
return new DelegateEqualityComparer<T>(equalityComparison);
}
}
然后围绕GroupBy方法编写包装器以接受Func<TKey, TKey, bool>
委托来代替IEqualityComparer<TKey>
参数。这些方法将委托包装在DelegateEqualityComparer<T>
实例中,并将其传递给相应的GroupBy方法。例如:
public static class EnumerableExt
{
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TKey, TKey, bool> equalityComparison)
{
return source.GroupBy(
keySelector,
DelegateEqualityComparer<TKey>.Create(equalityComparison);
}
}
最后,在您的调用网站上,您可以使用此表达式来表示equalityComparison
参数:
(a, b) => a.PeriodEnd.Equals(b.PeriodEnd)
&& a.Component.Code.Equals(b.Component.Code)
&& a.GroupCode.Equals(b.GroupCode)