45

I'm only using this code for an example. Assume I have the following Person class.

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

}

Main Program

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. is this the safe way of iterating over a concurrent dictionary? If not, what is the safe way for doing it?

  2. Lets say that I want to remove a Person object from the dictionary. I use the tryRemove method, but what do I do with the outPerson object? the removed Person from the dictionary is stored in it. What do I do with the outPerson object to clear it completely?

Charles Whitfield
  • 477
  • 1
  • 4
  • 7

2 Answers2

67

is this the safe way of iterating over a concurrent dictionary? If not, what is the safe way for doing it?

Yes, it's safe in that it won't throw an exception. If elements are added or removed after you start iterating, they may or may not be included in the iteration. From the GetEnumerator documentation:

The enumerator returned from the dictionary is safe to use concurrently with reads and writes to the dictionary, however it does not represent a moment-in-time snapshot of the dictionary. The contents exposed through the enumerator may contain modifications made to the dictionary after GetEnumerator was called.

Next:

I use the tryRemove method, but what do I do with the outPerson object?

Whatever you want with it, including nothing. You could just cast the dictionary to IDictionary<TKey, TValue> and call Remove, or just use TryRemove and ignore the variable afterwards:

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

Or you can use C# 7.0 feature Discards

dictionary.TryRemove(key, out _);

There's no concept of "clearing [the object] completely" - if you haven't got any references to it, it will be garbage collected. But either way, it's not in the dictionary any more (at least via that key). If you don't use the variable (ignored above) anywhere else in the code, it won't stop the object from being garbage collected.

rebornx
  • 407
  • 6
  • 21
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 5
    I saw this question and immediately knew there would be an answer from Jon Skeet.. lo and behold! – davnicwil Jul 21 '13 at 20:23
  • @ Jon Skeet - Would this be the correct way to cast it? IDictionary removefromColl=(IDictionary)personColl; – Charles Whitfield Jul 21 '13 at 20:30
  • 1
    @pawel I rolled back, since this invalidates the following paragraph about the `ignored` variable. Also please take a look at [this](https://meta.stackoverflow.com/a/260246/2441442) – Christian Gollhardt Jul 29 '18 at 05:45
2

Take a look at this article.

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.

Since TryRemove will remove the item from collection, you might need the value of the key.

It is safe to iterate it with foreach. You wont get an exception.

DarthVader
  • 52,984
  • 76
  • 209
  • 300
  • The OP *does* have the key. What makes you think they don't? And bear in mind that "I'm only using this code for an example" - there's no reason to think that the real code won't be using multiple threads. – Jon Skeet Jul 21 '13 at 20:19
  • I meant the value of what the key was corresponding to. It must be an american english thing. – DarthVader Jul 21 '13 at 20:20
  • But the OP's point is that they *don't* need to know the value corresponding to the key... so they weren't sure what to do with the `out` parameter. That's the way I answered it, anyway... – Jon Skeet Jul 21 '13 at 20:25