我写了一个像这样的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())
...
然而,这给了我
无法从用法推断出类型参数。尝试指定 显式的类型参数。
我对下一步感到茫然,这种分组肯定不会太难吗?
答案 0 :(得分:4)
Enumerable.GroupBy
允许您为键传递自定义相等比较器。但在您的情况下,密钥不是Address
对象 - 它是一个包含三个属性的匿名对象 - SiteRefNum
,SiteRefName
和Address
。当然,通过AddressComparer
比较这些键会导致错误。
你的第一个问题是使用复杂的对象作为关键属性。如果您不覆盖Equals
个对象的GetHashCode
和Address
方法,则会通过引用比较所有地址。对于每个地址实例,这当然是不同的。您可以提供Equals
和GetHashCode
实施来比较地址。
或者您可以修改查询以使用地址字符串进行分组:
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)
};
您可以使用方法语法进行查询,但我发现声明性查询语法更具可读性:)
答案 1 :(得分:1)
您可以尝试在Address类中覆盖Equals和GetHashCode(就像在比较器中一样):
public override bool Equals(object obj)
{
Address adr = obj as Address;
if (adr != null)
return adr.ToString() == this.ToString();
return false;
}
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}