c# - 无法从 Iesi.Collections.Generic ISet<T> 中删除项目

标签 c# wpf hashcode iesi-collections

我有一个类型的集合:
Iesi.Collections.Generic

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);
 }

但这是一个肮脏的解决方法。我正在尝试以优雅的方式执行此简单的删除:)。

更改类型

如果我更改 IList 中 ISet 的类型,它就可以正常工作。

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

当我想从此集合中删除某个项目时,它已被删除。

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

我无法从 ISet 中删除项目,所以缺少什么...?

感谢您的建议和解决方案。

最佳答案

这是一个非常简单的问题。只需下载 dotPeek 1.2 并启动符号服务器,然后您就可以检查 ISet.Remove() 的实际实现并了解它为何如此挑剔。正如@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

如您所见,Remove() 使用 Contains() 来实际测试是否应该删除元素。 Contains() 的作用是什么?基本上它是 Dictionary.Contains() 的包装

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

GetHashCode returns a value based on the current instance that is suited for hashing algorithms and data structures such as a hash table. Two objects that are the same type and are equal must return the same hash code to ensure that instances of System.Collections.HashTable and System.Collections.Generic.Dictionary work correctly.

请注意,重要的是:

1) 您的 GetHashCode() 无法更改。这意味着 GetHashCode() 使用的所有字段都不能更改。一旦您将元素插入到 Dictionary 中,就会调用其 GetHashCode() 并将其放入特定的存储桶中。当您以后有不同的GetHashCode()时,您将无法恢复它。 GetHashCode() 通过后,将调用您的 Equals 方法。确保您的字段是不可变的。

词典相关来源:

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 在该线程中的回答。

关于c# - 无法从 Iesi.Collections.Generic ISet<T> 中删除项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22858343/

相关文章:

java - 为数据库中的记录生成哈希 ID

java - 在java中实现好的hashCode函数?

c# - 将 WMI CimType 转换为 System.Type

c# - 如何在 ASP.NET 中将创建的 excel 文件保存到客户端电脑

wpf - ComboBox 项目的货币格式

java - 使用 hashCode 和 Arrays.equals 时潜在的哈希问题

c# - IOS项目如何生成IPA

c# - Monodroid 设计器缺少设备配置

c# - 自定义组合框样式

c# - 使用触发器绑定(bind) WPF Datagrid 单元格背景颜色