2011-07-31 17 views
2

這裏是例子:.NET如何確定LINQ中的對象「select new」?

class A 
{ 
    public long ParentId; 
    public string ParentName; 
    public string Name; 
} 

// list is IEnumerable<A> 
var selected = list 
    .Select(x => new { 
     parent = new { 
      id = x.ParentId, 
      name = x.ParentName 
     } 
     name = x.Name 
    }); 
var grouped = selected.GroupBy(x => x.parent); 

所以,作爲分組順利完成,我做結論,那不是爲兩個不同的實體創建parent如果兩者具有相同的ParentIdParentName。換句話說,如果list[i].ParentId == list[j].ParentIdlist[i].ParentName == list[j].ParentName,然後選擇selected[i].parent == selected[j].parent後。
對嗎?我想,new通過源集合在每次迭代中創建一個新對象。 .NET如何做到這一點?

回答

4

這是Equals如何被迫的問題。對於匿名類,當且僅當屬性匹配並且每個屬性均等時才返回true。

比較這兩種:

Console.WriteLine(new { A = 1, B = "a" } == new { A = 1, B = "a" }); //false 
Console.WriteLine(new { A = 1, B = "a" }.Equals(new { A = 1, B = "a" })); //true 
0

它不會調用==運算符。

它詢問EqualityComparer<T>.Default如果情況相同。 反過來,它從IEquatable執行,如果有任何,或Object.Equals方法作爲最後的手段,調用Equals

默認實現Equals支持引用類型的引用相等,以及值類型的按位相等。

但是,如果您需要爲平等設置自己的規則,則可以自由覆蓋該方法。

在你的例子中,parent如果是匿名類型。 C#編譯器逐個字段地生成EqualsGetHashCode實現,因爲顯然你不能自己提供它們。

+0

你的意思是,'parent'在這種情況下是值類型? –

+0

我編輯了答案來澄清。 –

0

每個.Net對象都實現了IComparer接口,並具有它自己的CompareTo方法的實現。 .Net只是使用這種方法來確定是否有相同的東西,在這種情況下.net只是檢查兩個對象公共屬性具有相同的值,因此它們是相等的。

編輯:對不起,我混淆了IComparer CompareTo與object.Equals,每個對象實現Equals方法,並作爲一個例子,String類重寫此方法,只是檢查兩個字符串包含相同的值不引用相同的內存地址。

+0

這是錯誤的。 'System.Object' [不](http://msdn.microsoft.com/en-us/library/system.object.aspx)實現'IComparable'(這可能是你的意思)。 –

+0

但是如果兩個字段的字段相等,則'A'的兩個不同實例將不相等。 –

1

GroupBy使用標準的散列+等於的方法(共同用HashtableDictionary<,>等),這就是說:

  • GetHashCode定義明確的不相等(不同時)和可能平等(當相同)
  • 等於(IEquatable<T>.Equalsobject.Equals)限定平等

你的組通過投影比較ParentName,以便在比較項目時使用。由於string已定義好GetHashCode/Equals,這工作正常。

重新您的最後一個問題:

我認爲,新通過源收集每次迭代中創建新的對象。

嚴格來說,是的。但它只列舉一次,所以這不是問題。即使沒有,匿名類型new {...}本身也具有基於組件成員的相等定義。

0

好覆蓋的.Net的defualt比較的行爲,你應該做這樣的事情:

class A 
{ 
    public long ParentId; 
    public string ParentName; 
    public string Name; 


    public override bool Equals(object obj) 
    { 
     if (ReferenceEquals(null, obj)) 
      return false; 
     if (ReferenceEquals(this, obj)) 
      return true; 
     if (obj.GetType() != typeof(A)) 
      return false; 
     var other=(A) obj; 
     return Equals(other.ParentId, ParentId) && Equals(other.ParentName, ParentName); 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      return (ParentName.GetHashCode() * 397)^ParentId.GetHashCode(); 
     } 
    } 
} 
+0

這不是最好的方法。相反,您應該實現'IEquatable '並從「普通對象」「Equals」中調用它的「Equals」。 –

相關問題