我写了这样的GroupBy语句:

var aggregated = sitesWithLive
    .GroupBy(s => new {s.SiteRefNum, s.SiteRefName, s.Address})
    .Select(g =>
        new Site
        {
            SiteRefNum = g.Key.SiteRefNum,
            SiteRefName = g.Key.SiteRefName,
            Address = g.Key.Address,
            ContractLive = g.Max(x => x.ContractLive)
        });


分组中的Address是复杂类型:

public class Address
{
    public string Name { get; set; }
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string Line3 { get; set; }
    public string Line4 { get; set; }
    public string PostCode { get; set; }

    public bool IsEmpty()
    {
        return GetType().GetProperties()
            .Where(a => a.GetValue(this) is string)
            .Select(a => (string)a.GetValue(this))
            .All(string.IsNullOrEmpty);
    }

    public override string ToString()
    {
        var addr = Line1 + "," + Line2 + "," + Line3 + "," + Line4 + "," + PostCode;
        var address = Regex.Replace(addr, @"^,+|,{2,}|,(?=[\w.])", ", ");
        return address;
    }
}


但是,这不能按地址正确分组,而是为每个元素返回一个单独的组。

据我了解,要按复杂类型分组,必须提供IEqualityComparer,因此我创建了以下内容:

public class AddressComparer : IEqualityComparer<Address>
{
    public bool Equals(Address x, Address y)
    {
        return x.ToString() == y.ToString();
    }

    public int GetHashCode(Address obj)
    {
        return 1;
    }
}


并像这样提供(上面的子集):

var aggregated = sitesWithLive.GroupBy(s => new {s.SiteRefNum, s.SiteRefName, s.Address}, new AddressComparer())
...


但是这给了我


不能从用法中推断出类型实参。尝试指定
类型参数明确。


我对下一步不知所措,这种分组肯定不会太难吗?

最佳答案

Enumerable.GroupBy允许您传递键的自定义相等比较器。但是在您的情况下,密钥不是Address对象-它是包含三个属性-SiteRefNumSiteRefNameAddress的匿名对象。当然,传递AddressComparer来比较此类键将导致错误。

您的第一个问题是使用复杂对象作为关键属性。如果不为Equals对象覆盖GetHashCodeAddress方法,则将通过引用比较所有地址。对于每个地址实例,这当然是不同的。您可以提供EqualsGetHashCode实现来比较地址。

或者,您可以修改查询以使用地址字符串进行分组:

var aggregated =
    from s in sitesWithLive
    group s by new {
       s.SiteRefNum,
       s.SiteRefName,
       Address = s.Address.ToString() // here we group by string
    } into g
    select new Site
    {
        SiteRefNum = g.Key.SiteRefNum,
        SiteRefName = g.Key.SiteRefName,
        Address = g.First().Address, // here we just get first address object
        ContractLive = g.Max(x => x.ContractLive)
    };


您可以使用方法语法进行查询,但是我发现声明性查询语法更易读:)

关于c# - 对具有复杂类型的多个属性进行分组,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42650526/

10-10 18:29
查看更多