According to the documentation on GetEnumerator for ConcurrentDictionary (the highlighting is mine):
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.
Whether or not you consider this threadsafe depends on exactly what semantics you require. Note that if you do want a snapshot, you can get this by calling the ToArray()
method:
IEnumerable<Dto> dtos = concurrentDictionary.ToArray().Select(p => p.Value);
According to the documentation, ToArray()
returns:
A new array containing a snapshot of key and value pairs copied from
the System.Collections.Concurrent.ConcurrentDictionary.
(Note that this is the ToArray
method belonging to ConcurrentDictionary
, NOT the Linq ToArray()
method, which will use the enumerator.)
Finally, note that, as has already been pointed out, if your DTOs are mutable, all bets are off. You may get a snapshot of the list, but there is nothing preventing the contents of that list being changed on another thread.
EDIT:
From reading the page that you linked to in the comments, the takeaway point is this:
All public and protected members of ConcurrentDictionary
are thread-safe and may be used concurrently from multiple threads.
However, members accessed through one of the interfaces the
ConcurrentDictionary implements, including extension
methods, are not guaranteed to be thread safe and may need to be
synchronized by the caller.
This tells us that Linq is not guaranteed to be threadsafe when used with ConcurrentDictionary
. for each
should be fine, since that will call GetEnumerator
which has the guarantee mentioned at the beginning of this post. My hunch is that Select
would also be fine, but it is not guaranteed to be.
So to answer the questions in your code:
IEnumerable<Dto> dtos = concurrentDictionary.Select(p => p.Value);
ArrayList arrayList = new ArrayList();
foreach (object obj in dtos)
{
//is it thread safe accessing the Dto like this and adding them to new arraylist?
arrayList.Add(obj);
}
Probably, but it is not guaranteed, and in any case, this gives you no benefit over ToArray()
, so I would replace everything here with:
KeyValuePair<int, Dto>[] dtoArray = concurrentDictionary.ToArray();
Secondly:
//Is it thread safe accessing the Dto's properties like this?
//Of course only for reading purposes.
string name = ((Dto) arrayList[0]).Name;
Whether this is safe or not has nothing to do with ConcurrentDictionary
and everything to do with your implementation of the Name
method in Dto
. Yes, you can access the Dto
safely, but any properties or methods you access would need to be threadsafe. If you have used ToArray()
as suggested above, then
Dto dto = dtoArray[0].Value
is threadsafe, but
string name = dtoArray[0].Value.Name
depends on the implementation of Name
.