2017-03-07 96 views
2

我已經寫了的GroupBy聲明,如下所示:的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

Omg,ToString()裏面發生了什麼。爲什麼你需要這裏的正則表達式?從開始建立正確的字符串不是更好嗎?另外,你在GetHashCode中返回1,這是正確的,但效率非常低。 – eocron

+2

@eocron:那真的不是真的要你判斷,真的 - 也許他正在規範來自第三方的一些地址數據?相反,建議一種替代方法來比較對象會更好。 – caesay

回答

4

Enumerable.GroupBy允許您傳遞按鍵的自定義相等比較器。但在您的情況下,密鑰不是Address對象 - 它是包含三個屬性的匿名對象 - SiteRefNum,SiteRefNameAddress。當然,通過AddressComparer來比較這些鍵會導致錯誤。

而你的第一個問題是使用複雜的對象作爲關鍵屬性。如果您不覆蓋EqualsGetHashCode方法的Address對象,則所有地址將通過引用進行比較。每個地址實例當然不同。您可以提供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) 
    }; 

您可以使用方法語法查詢,但我發現聲明查詢語法更具可讀性:)

+0

關於爲什麼它目前沒有工作的解釋很好 - 但我認爲這裏重要的是'Address'需要有一個Equals和GetHashCode實現,並且這裏有點不知所措。 – caesay

1

你可以嘗試覆蓋地址類中的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(); 
} 
+0

注意 - 你應該總是重寫'GetHashCode'以及 –

+0

只是注意到它...我忘記了GetHashCode – PinBack