您当前的位置: 首页 > 

寒冰屋

暂无认证

  • 0浏览

    0关注

    2286博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

在C#中有效地使用列表作为字典键

寒冰屋 发布时间:2020-03-06 20:36:42 ,浏览量:0

目录

介绍

概念化这个混乱

编码此混乱

警告

使用其他容器

有时有必要将集合用作字典键,但是这可能会导致性能下降并且不安全。以下是使它更快更安全的方法。

  • 下载源4.9 KB
介绍

使用C#进行功能样式编程时,您最终可能会遇到需要按项目的有序列表来键入字典的情况。有好的方法,但不是非常好的方法。本文旨在为您提供一种将列表用作字典键的有效且相对安全的方法。

概念化这个混乱

字典键必须具有可比性,以确保相等性,必须提供适当的哈希码,并且必须不可变。这些要求使使用列表作为字典键有点麻烦,因为列表通常不提供值语义——在这种情况下,是逐项比较和适当的哈希码。也许更糟的是,列表允许您随时修改它们。

总之,这里有两个主要问题,一个是逐项比较列表不是很有效,并且使用标准IList实现作为字典键从根本上是不安全的,因为可以随时对其进行修改。

我们可以通过要求使用IReadOnlyList来或多或少地解决后者,后者提供类似列表的访问,而不需要修改列表的方法。不过,当我们声明KeyList类时,我们将在其中添加一个Add()方法。这样做的原因是允许您首先填写列表。如果我们想更加安全,则可以取消该Add()方法,并强制您将这些项作为数组传递给KeyList的构造函数。未执行此操作的原因是为了提高性能。KeyList的主要目的是性能,将数据传递给构造函数将需要一个副本。副本不一定很慢,但我们不需要它——我们在这里没事,因为任何采用IReadOnlyList的操作都不会看到Add() 方法,这样,我们就避免了虚假的副本。

前者需要做更多的工作。我们必须在KeyList上实现值相等语义。但是,在这里,我们提出了一个重要的技巧:在将每个项目添加到列表时,我们都会重新计算哈希码,这样我们就不必在以后进行计算。然后,我们将该哈希码用作相等性检查的一部分,以在它们不相等时短路。接下来,让我们看一下该KeyList类的代码。

编码此混乱
sealed class KeyList : IReadOnlyList, IEquatable
{
    int _hashCode;
    List _items;
    public KeyList()
    {
        _items = new List();
        _hashCode = 0;
    }
    public KeyList(int capacity)
    {
        _items = new List(capacity);
        _hashCode = 0;
    }
    public T this[int index] => _items[index];

    public int Count => _items.Count;

    public IEnumerator GetEnumerator()
    {
        return _items.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public void Add(T item)
    {
        _items.Add(item);
        if (null != item)
            _hashCode ^= item.GetHashCode();
    }
    public override int GetHashCode()
    {
        return _hashCode;
    }
    public bool Equals(KeyList rhs)
    {
        if (ReferenceEquals(this, rhs))
            return true;
        if (ReferenceEquals(rhs, null))
            return false;
        if (rhs._hashCode != _hashCode)
            return false;
        var ic = _items.Count;
        if (ic != rhs._items.Count)
            return false;
        for(var i = 0;i            
关注
打赏
1665926880
查看更多评论
0.0426s