m.e*_*son 2 .net c# linq group-by
我写了一个 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)
});
Run Code Online (Sandbox Code Playgroud)
在分组中是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;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,这不能按地址正确分组,而是为每个元素返回一个单独的组。
我的理解是,要按复杂类型分组,您必须提供一个,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;
}
}
Run Code Online (Sandbox Code Playgroud)
并像这样提供它(上面的子集):
var aggregated = sitesWithLive.GroupBy(s => new {s.SiteRefNum, s.SiteRefName, s.Address}, new AddressComparer())
...
Run Code Online (Sandbox Code Playgroud)
然而,这给了我
无法从用法推断出类型参数。尝试明确指定类型参数。
我对下一步感到茫然,这种分组肯定不会太难吗?
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)
};
Run Code Online (Sandbox Code Playgroud)
您可以使用方法语法进行查询,但我发现声明式查询语法更具可读性:)
| 归档时间: |
|
| 查看次数: |
435 次 |
| 最近记录: |