2014-04-04 22 views
2

我有類型的集合:
Iesi.Collections.Generic無法從Iesi.Collections.Generic的ISet刪除項目<T>

public ISet<ItemBinding> ItemBindings { get; set; } 

其中ItemBindingDomain.Model

我以這種方式初始化集合:

ItemBindings = new HashedSet<ItemBinding>(); 

我用成員填充集合。

當我想從這個集合中刪除一個項目時,我無法刪除它。

private void OnRemove(ItemBinding itemToRemove) { 
    ItemBindings.Remove(itemToRemove); 
} 

即使是itemToRemove具有相同hashCode從收集的項目。

我也試圖找到該項目的收集,保存在一個變量,並將其刪除:

private void OnRemove(ItemBinding itemToRemove) { 
    var foundItem = ItemBindings.Single(x => x.Id == itemToRemove.Id); // always if found 
    ItemBindings.Remove(foundItem); 
} 

但這不起作用。

該工程確定的解決方法是這樣的:

private void OnRemove(ItemBinding itemToRemove) { 
    var backUpItems = new List<ItemBinding>(ItemBindings); 
    backUpItems.Remove(itemToRemove); 

    ItemBindings.Clear(); 
    ItemBindings.AddAll(backUpItems); 
} 

但這是一個骯髒的解決方法。我試圖做到這一點簡單刪除在一個優雅的方式:)。

更改類型

如果我改變ISET和在IList中它工作正常的類型。

public IList<ItemBinding> ItemBindings { get; set; } 
ItemBindings = new List<ItemBinding>(); 

當我想從這個集合中刪除一個項目時,它被刪除了。

private void OnRemove(ItemBinding itemToRemove) { 
    ItemBindings.Remove(itemToRemove); 
} 

我失蹤的方式,我不能從ISet刪除項目...?

謝謝你的建議,解決方案。

+0

有人遇到過這樣的問題? – meorfi

+0

我們有同樣的問題,對IList的改變正在爲我們工作! – lxalln

+0

什麼價值的HashSet 卸下襬臂()的返回 - 如果去掉這些對象存在並且已經被移除,它應該返回TRUE,或FALSE如果項目不能被發現。你的情況如何? – PhillipH

回答

2

這是非常簡單的問題。只需下載dotPeek 1.2並啓動符號服務器&,然後就可以檢查ISet.Remove()的ACTUAL實現並瞭解它爲什麼很挑剔。作爲@HansPassant說,它可能是GetHashCode()方法的情況下,或在實際執行HashedSet

至於我的猜測;看看DictionarySet(基類的HashedSet):

https://www.symbolsource.org/Public/Metadata/Default/Project/NHibernate/3.0.0.Alpha2/Release/All/Iesi.Collections/Iesi.Collections/Generic/DictionarySet.cs

正如你所看到的,刪除()使用contains()方法來實際測試它是否應該刪除元素與否。 Contains()是做什麼的?基本上它是圍繞Dictionary.Contains包裝()

http://msdn.microsoft.com/en-us/library/ms182358(v=vs.80).aspx

GetHashCode返回基於當前實例的值,該值是 適合哈希算法和數據結構,諸如哈希 表。兩個對象是相同類型和相等,必須返回 相同的散列碼,以確保和System.Collections.Generic.Dictionary System.Collections.HashTable的情況下 正常工作。

1)你的GetHashCode()不能改變

請注意,這一點很重要。這意味着GetHashCode()使用的所有字段都不能更改。只要你將元素插入到Dictionary中,它的GetHashCode()就會被調用,並被放到特定的存儲區中。如果稍後有不同的GetHashCode(),則無法恢復。 GetHashCode()過後,等於方法將被稱爲。確保你的領域是不可變的。從字典

相關來源:

private int FindEntry(TKey key) 
{ 
    if ((object) key == null) 
    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key); 
    if (this.buckets != null) 
    { 
    int num = this.comparer.GetHashCode(key) & int.MaxValue; 
    for (int index = this.buckets[num % this.buckets.Length]; index >= 0; index = this.entries[index].next) 
    { 
     if (this.entries[index].hashCode == num && this.comparer.Equals(this.entries[index].key, key)) 
     return index; 
    } 
    } 
    return -1; 
} 

看到這個線程如何重寫equals()和GetHashCode()方法:

Why is it important to override GetHashCode when Equals method is overridden?

通知書@Albic答案,在該線程。

0

我無法重現此行爲。

private class ItemBinding 
    { 
     public string ID { get; set; } 
    } 

    [TestMethod] 
    public void TestMethod1() 
    { 
     System.Collections.Generic.HashSet<ItemBinding> set = new System.Collections.Generic.HashSet<ItemBinding>(); 
     ItemBinding item1 = new ItemBinding() { ID = "Jaffa" }; 
     set.Add(item1); 
     Assert.IsTrue(set.Count == 1); 
     set.Remove(item1); 
     Assert.IsTrue(set.Count == 0); 

     ItemBinding item2 = new ItemBinding() { ID = "Moon" }; 
     set.Add(item2); 
     ItemBinding item3 = new ItemBinding() { ID = "Moon" }; 

     Assert.IsTrue(item2.GetHashCode() != item3.GetHashCode()); 
     Assert.IsTrue(set.Remove(item3) == false); 
     Assert.IsTrue(set.Count == 1); 

    } 

上述測試顯示Hashset按預期工作。是否有可能陷入第二次測試中所顯示的陷阱,即比較兩個具有相同值的類的實例,但實際上是不同的類實例(因此GetHashCode相等性測試失敗?)。

如果您可以在此更改發佈的代碼以更準確地表示您的特定問題,那將會有所幫助。

+0

你應該使用'Iesi.Collections.Generic的ISet '和具體的實現,而不是'System.Collections.Generic.HashSet '。另外,測試方法應該通過NHibernate持久化到DB,並且從DB加載代表性。 –

+0

Russ,OP說他們用ItemBindings = new HashSet 我相信?哦 - 好吧,我看到我的錯誤,我認爲OP將錯誤的HashSet設置爲HashedSet,但HashesSet是Iesi中的具體實現,而不是System.Collections.Hashset的錯字。我沒有可用的反射/ ILSpy NHibernate的副本,但多數民衆贊成我如何去解決難題。 – PhillipH

+0

我懷疑他們遇到的問題與此有關 - http://weblogs.asp.net/ricardoperes/nhibernate-pitfalls-sets-and-hash-codes –

0

您可以嘗試使用...

private void OnRemove(ItemBinding itemToRemove) 
{ 
    ItemBindings.RemoveWhere(x => x.Id == itemToRemove.Id); 
}