所以我已经在SO和其他地方看了大约20个例子,但没有找到一个涵盖我正在尝试做的事情。这 - 我可以内联指定我的显式类型比较器吗? -看起来像我需要的,但没有走得足够远(或者我不明白如何进一步)。

  • 我有一个LoadData列表,LoadData对象具有引用和值类型的字段
  • 需要对ref和value字段的混合进行分组,将输出投影到匿名类型
  • 需要(我认为)提供一个自定义的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);

此组,但仍有重复。

  1. 如何指定自定义代码来比较GroupBy字段?例如,组分可以按组分进行比较。密码。
有帮助吗?

解决方案

这里的问题是你的键类型是匿名的,这意味着你不能声明一个实现的类 IEqualityComparer<T> 为该密钥类型。虽然会是 可能的 要编写一个比较器,以自定义方式(通过泛型方法,委托和类型推断)比较匿名类型的相等性,它不会非常愉快。

最简单的两个选项可能是:

  • 通过重写Equals/GetHashCode使匿名类型"just work"in PeriodEndDtoComponentDto.如果你想在任何地方使用自然平等,这可能是最明智的选择。我建议实施 IEquatable<T> 也一样
  • 不要使用匿名类型进行分组-使用命名类型,然后您可以复盖 GetHashCodeEquals 在这一点上,或者你可以用正常的方式编写一个自定义相等比较器。

编辑: ProjectionEqualityComparer 真的行不通。写一些类似的东西是可行的--一种 CompositeEqualityComparer 这允许您从几个"投影+比较器"对创建相等比较器。与匿名类型相比,这将是非常丑陋的。

其他提示

编辑:

正如Jon Skeet所指出的那样,这个解决方案似乎比它更好,如果你不仔细考虑它,因为我忘记了实现GetHashCode。必须实现GetHashCode使得这种方法,正如Jon在他的回答中所说,"不是非常愉快。"据推测,这也是对(所谓的"莫名其妙的")缺席的解释。 EqualityComparer<T>.Create() 框架中。我会留下答案供参考,作为不做什么的例子,也可以是有益的。

原答案:

你可以使用 Comparer<T>.Create 在.NET4.5中引入的模式(但在 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)
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top