Partially thread-safe dictionary

前端 未结 4 1409
野性不改
野性不改 2021-01-20 15:16

I have a class that maintains a private Dictionary instance that caches some data.

The class writes to the dictionary from multiple threads using a

4条回答
  •  时光说笑
    2021-01-20 15:30

    EDIT: I personally believe the below code is technically answering your question correctly (as in, it provides a way to enumerate over the values in a collection without creating a copy). Some developers far more reputable than I strongly advise against this approach, for reasons they have explained in their edits/comments. In short: This is apparently a bad idea. Therefore I'm leaving the answer but suggesting you not use it.


    Unless I'm missing something, I believe you could expose your values as an IEnumerable without needing to copy values by using the yield keyword:

    public IEnumerable Values {
        get {
            using (sync.ReadLock()) {
                foreach (MyClass value in cache.Values)
                    yield return value;
            }
        }
    }
    

    Be aware, however (and I'm guessing you already knew this), that this approach provides lazy evaluation, which means that the Values property as implemented above can not be treated as providing a snapshot.

    In other words... well, take a look at this code (I am of course guessing as to some of the details of this class of yours):

    var d = new ThreadSafeDictionary();
    
    // d is empty right now
    IEnumerable values = d.Values;
    
    d.Add("someKey", "someValue");
    
    // if values were a snapshot, this would output nothing...
    // but in FACT, since it is lazily evaluated, it will now have
    // what is CURRENTLY in d.Values ("someValue")
    foreach (string s in values) {
        Console.WriteLine(s);
    }
    

    So if it's a requirement that this Values property be equivalent to a snapshot of what is in cache at the time the property is accessed, then you're going to have to make a copy.

    (begin 280Z28): The following is an example of how someone unfamiliar with the "C# way of doing things" could lock the code:

    IEnumerator enumerator = obj.Values.GetEnumerator();
    MyClass first = null;
    if (enumerator.MoveNext())
        first = enumerator.Current;
    

    (end 280Z28)

提交回复
热议问题