2014-11-06 106 views
3

我想將一個grouppedList傳遞給幾個函數,但是當嘗試使用一個類而不是一個匿名類型進行分組時,我得到了奇怪的結果。在以下示例中,匿名類型按預期返回2個結果,但具體類返回5,就好像它沒有分組一樣。Linq to Sql Group按類

問題:是否有可能通過具體的類來執行Linq to Sql Group?

public class person 
{ 
    public string Name; 
    public string State; 
} 

public class personGroup 
{ 
    public string State; 
    public personGroup(string personState) 
    { 
     State = personState; 
    } 
} 


void Main() 
{ 
    var people = new List<person>(); 
    people.Add(new person {Name = "Bob", State = "Tx"}); 
    people.Add(new person {Name = "Bill", State = "Tx"}); 
    people.Add(new person {Name = "Tracy", State = "Tx"}); 
    people.Add(new person {Name = "Steve", State = "Md"}); 
    people.Add(new person {Name = "Kelly", State = "Md"}); 

    var groupedPeople = people.GroupBy (p => p.State); 
    groupedPeople.Count().Dump();//Returns 2 

    var morePeople = people.GroupBy (p => new personGroup(p.State)); 
    morePeople.Count().Dump();//Returns 5 
} 
+1

在這個問題中沒有「SQL」。我想你只是說LINQ。 – 2014-11-06 21:26:43

回答

4

GroupBy方法使用EqualityComparer<T>.Default來比較沒有提供自定義IEqualityComparer(您沒有提供一個)有問題的項目。這將基於T類型的IEquatable<T>的實現,如果有的話,如果沒有,那麼它將簡單地使用該類型的object.Equalsobject.GetHashCode

您的自定義類型不提供任何實現,它完全依賴於object中定義的實現,對於引用類型,該實現基於對象的引用。您創建的每個personGroup對象都有不同的參考,因此不同。

匿名類型不使用默認的平等behvaior;它們覆蓋EqualsGetHashCode的定義,以取決於它們表示的每個屬性的標識。

如果你想使用自己定製的類型進行分組,並默認平等語義不是你想要的,你要麼需要提供自定義IEqualityComparer實現,或覆蓋EqualsGetHashCode在類型題。

+0

我看到如何覆蓋Equals,但是我將使用GetHashCode,它是否需要對每個組都是唯一的,或者我可以只返回1.GetHashCode – SumGuy 2014-11-06 21:36:37

+0

@SumGuy閱讀該方法的文檔,看看實施它時需要遵循的準則。在這個特定情況下,你可能只需要返回該組正在包裝的'State'的哈希碼,但在更復雜的情況下,你可能需要做更多的事情來生成一個好的哈希。 – Servy 2014-11-06 21:37:57

3

在第二組中,有5組,因爲密鑰總是不同的。 personGroups通過引用進行比較,並且所有對象都有不同的參考。您需要覆蓋personGroup類中的EqualsGetHashCode方法,以根據狀態比較您的實例,或實施IEqualityComparer<personGroup>並將其傳遞到GroupBy

+0

你如何將它傳遞給GroupBy? – SumGuy 2014-11-06 21:36:56

+1

'people.GroupBy(p => new personGroup(p.State),new MyEqualityComparer())' – 2014-11-06 21:37:33

0

由於Servy上面已經說過,您需要創建一個PersonGroup類型的自定義IEqualityComparer以便您的示例正常工作。

我已經遇到過很多我自己,所以我創建了一個通用的EqualityComparer,它可以與任何模型(使用屬性)一起工作!

/// <summary> 
/// Given two models, return TRUE if all the properties are equal, 
/// else return FALSE 
/// </summary> 
/// <typeparam name="TModel">Type of the models being compared</typeparam> 
public class PropertyEqualityComparer<TModel> : IEqualityComparer<TModel> 
{ 
    public bool Equals(TModel x, TModel y) 
    { 
     PropertyInfo[] props = typeof(TModel).GetProperties(); 
     foreach (PropertyInfo prop in props) 
     { 
      if (!Object.Equals(prop.GetValue(x), prop.GetValue(y))) 
      { 
       return false; 
      }  
     } 
     return true; 
    } 

    public int GetHashCode(TModel obj) 
    { 
     int hash = 1; 
     PropertyInfo[] props = typeof(TModel).GetProperties(); 
     foreach (PropertyInfo prop in props) 
     { 
      hash ^= prop.GetValue(obj).GetHashCode(); 
     } 
     return hash; 
    } 
} 

有了這門課,你將能夠做到你所想。

// NOTE: Use properties instead of public variables 
public class Person 
{ 
    public string Name { get; set; } 
    public string State { get; set; } 
} 

// NOTE: Use properties instead of public variables 
public class personGroup 
{ 
    public string State { get; set; } 
} 

void Main() 
{ 
    var people = new List<Person>(); 
    people.Add(new Person{Name = "Bob", State = "Tx"}); 
    people.Add(new Person{Name = "Bill", State = "Tx"}); 

    var morePeople = people.GroupBy(p => new PersonGroup{State = p.State}, new PropertyEqualityComparer<PersonGroup>()); 
    morePeople.Count(); 
}