【问题标题】:Is this the proper way to iterate over Concurrentdictionary in C#这是在 C# 中迭代​​ Concurrentdictionary 的正确方法吗
【发布时间】:2013-07-20 12:42:40
【问题描述】:

我只是将此代码用作示例。假设我有以下 Person 类。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace dictionaryDisplay
{
class Person
{
    public string FirstName { get; private set;}
    public string LastName { get; private set; }

    public Person(string firstName, string lastName)
    {
        this.FirstName = firstName;
        this.LastName = lastName;

    }

    public override string ToString()
    {
        return this.FirstName + " " + this.LastName;
    }
}

}

主程序

static void Main(string[] args)
    {
        ConcurrentDictionary<int, Person> personColl = new ConcurrentDictionary<int,   Person>();

        personColl.TryAdd(0, new Person("Dave","Howells"));
        personColl.TryAdd(1, new Person("Jastinder","Toor"));

        Person outPerson = null;
        personColl.TryRemove(0, out outPerson);


        //Is this safe to do?
        foreach (var display in personColl)
        {
            Console.WriteLine(display.Value);
        }





    }
  1. 这是迭代并发字典的安全方法吗?如果不是,那么安全的方法是什么?

  2. 假设我想从字典中删除一个 Person 对象。我使用 tryRemove 方法,但我该如何处理 outPerson 对象?从字典中删除的 Person 存储在其中。我该如何处理 outPerson 对象来完全清除它?

【问题讨论】:

  • 不想挑剔,但您不会错过 using 声明:using System.Collections.Concurrent; ?
  • 它在那里,只是没有包含它。

标签: c# concurrent-programming


【解决方案1】:

这是迭代并发字典的安全方法吗?如果不是,那么安全的方法是什么?

是的,它不会抛出异常是安全的。如果在开始迭代后添加或删除元素,它们可能包含在迭代中,也可能不包含在迭代中。来自GetEnumerator documentation:

从字典返回的枚举器可以安全地与字典的读取和写入同时使用,但它并不代表字典的即时快照。通过枚举器公开的内容可能包含调用 GetEnumerator 后对字典所做的修改。

下一步:

我使用了 tryRemove 方法,但是我该如何处理 outPerson 对象呢?

随心所欲,包括任何东西。您可以将字典转换为IDictionary&lt;TKey, TValue&gt; 并调用Remove,或者只使用TryRemove 并在之后忽略该变量:

Person ignored;
dictionary.TryRemove(key, out ignored);

或者您可以使用 C# 7.0 功能 Discards

dictionary.TryRemove(key, out _);

没有“完全清除[对象]”的概念-如果您没有对它的任何引用,它将被垃圾收集。但无论哪种方式,它不再在字典中(至少通过那个键)。如果您不在代码中的其他任何地方使用变量(上面的ignored),它不会阻止对象被垃圾回收。

【讨论】:

  • 我看到了这个问题,马上就知道 Jon Skeet 会有答案。你瞧!
  • @ Jon Skeet - 这是正确的投射方式吗? IDictionary removefromColl=(IDictionary)personColl;
  • @pawel 我回滚了,因为这会使下面关于ignored 变量的段落无效。也请看this
【解决方案2】:

看看this的文章。

TryRemove() was added to attempt atomic, safe removes.

    To safely attempt to remove a value we need to see if the key exists first, this checks for existence and removes under an atomic lock.

由于 TryRemove 将从集合中删除项目,因此您可能需要键的值。

使用 foreach 迭代它是安全的。你不会得到例外。

【讨论】:

  • OP确实有钥匙。是什么让你认为他们没有?请记住,“我只是将这段代码用作示例”——没有理由认为真正的代码不会使用多线程。
  • 我的意思是键对应的值。一定是美式英语。
  • 但是 OP 的观点是他们不需要需要知道键对应的值...所以他们不确定如何处理 @987654323 @ 范围。反正我就是这么回答的……
猜你喜欢
  • 2017-03-02
  • 2014-02-21
  • 1970-01-01
  • 1970-01-01
  • 2010-09-16
  • 1970-01-01
  • 2013-09-25
  • 1970-01-01
  • 2021-12-11
相关资源
最近更新 更多