3

我目前正在从事一个项目,我必须管理大量独特的元素。每个元素都有约 20 个属性,每个元素都有一个公共属性 DateTime。

属性 DateTime 不是唯一的,所以我不能使用通用字典来存储我的数据。

目前我将这些元素放入 ObservableCollection 中,但是从集合中删除元素的性能非常慢,我最终要等待约 20 秒才能从约 25.000 个元素的集合中删除约 7000 个元素。

(搜索操作似乎非常有效,从 300.000 个元素的未排序集合中找到 80 个随机选择的元素只需要大约 30 毫秒)。

每个元素通过简单地返回 DateTime.GetHashCode() 来实现 GetHashCode() 方法。

我认为使用 HashSet 而不是 ObservableCollection 会大大提高我的性能,但它似乎根本没有效果......

使用通用字典更糟糕......

如果元素具有“好的”散列函数(很少有元素具有相同的散列码),HashSet 不是比 ObservableCollection 更强大吗?

4

3 回答 3

3

您必须覆盖对象的Equals方法。

因为HashSet使用内部IEqualityComparer实例,该实例通常首先检查 (null),然后使用重写的Equals方法将“非空”项与另一个项进行比较:

class MyObject
{
    public Guid Id { get; set; }

    public override bool Equals(object other)
    {
        if (other is MyObject)
        {
            // use the 'Id' property as identifier

            MyObject myObj = (MyObject)obj;
            return myObj.Id == this.Id;
        }

        // is not a 'MyObject' based object
        return base.Equals(other);
    }
}

您还可以使用字符串或与您的对象可比较的任何其他类型的对象。

编辑:

所以你可以使用 HashSet 而不是OberservableCollection。最后一个集合类型通常较慢,因为在每次集合更改(添加、删除、清除、插入等)时,都会触发PropertyChangedCollectionChanged事件。

于 2012-05-20T18:27:29.080 回答
2

ObservableCollection您可以通过减少更改通知来优化性能。我编写了一个ItemCollection带有更新机制(BeginUpdate/ EndUpdate)的自定义集合类 the :

  ItemCollection<Customer> customers = new ItemCollection<Customer>
  customers.BeginUpdate();
  customers.Add( new Customer( "Joe", "Smith" ) );
  customers.Add( new Customer( "Mary", "Jones" ) );
  customers.Add( new Customer( "Lisa", "Black" ) );
  customers.Add( new Customer( "Peter", "Brown" ) );
  customers.EndUpdate();

包含源代码的文章:基于 XAML 的应用程序的表示模式

于 2012-05-24T07:20:30.727 回答
2

好吧,马塞尔的回答是正确的,但如果性能真的很重要,你可以稍微改进他的 equals 方法:

class MyObject
{
    public Guid Id { get; set; }

    public override bool Equals(object other)
    {
        MyObject myObj = obj as MyObject;

        if (myObj != null)
        {
            // use the 'Id' property as identifier
            return myObj.Id == this.Id;
        }

        // is not a 'MyObject' based object
        return base.Equals(other);
    }
}

使用这种方法,您可以避免使用昂贵的函数来检查对象是否属于特定类型,只需调用一次并执行快速空值检查即可。有关它的更多信息,您可以查看Eric 的这篇文章

于 2012-05-24T07:38:25.493 回答