Frage ConcurrentDictionary.GetOrAdd führt immer Delegate-Methode aus


Ich stelle fest, dass GetOrAdd () den Factory-Delegaten immer ausführt, auch wenn der Wert im Wörterbuch vorhanden ist. Beispielsweise:

class Program
{
    private static ConcurrentDictionary<string, string> _cache = new ConcurrentDictionary<string, string>();

    static void Main(string[] args)
    {
        string value;

        value = GetValueFromCache("A"); // cache is empty, CacheValueFactory executes, A is added
        value = GetValueFromCache("A"); // cache contains A, CacheValueFactory executes
        value = GetValueFromCache("C"); // cache contains A, CacheValueFactory, C is added
        value = GetValueFromCache("A"); // cache contains A and C, CacheValueFactory executes
    }

    private static string GetValueFromCache(string key)
    {
        string val = _cache.GetOrAdd(key, CacheValueFactory(key));

        return val;
    }

    private static string CacheValueFactory(string key)
    {
        if (key == "A")
            return "Apple";
        else if (key == "B")
            return "Banana";
        else if (key == "C")
            return "Cherry";

        return null;
    }
}

Beim ersten Aufruf von GetValueFromCache ("A") ist der Cache leer und A: Apple wird hinzugefügt. Als ich mit dem Debugger eintrat, bemerkte ich, dass die CacheValueFactory () -Methode beim zweiten und dritten Aufruf von GetValueFromCache ("A") immer ausgeführt wird. Wird das erwartet? Ich hätte gedacht, dass die Delegate-Methode nicht ausgeführt werden würde, wenn der Schlüssel im Wörterbuch vorhanden ist.


22
2017-12-09 16:00


Ursprung


Antworten:


Der Grund dafür ist, dass Sie nicht vorbeigehen CacheValueFactory als Delegierter, sondern werte die Funktion prompt aus und übergibt den resultierenden Wert. Dies führt dazu, dass Sie die Überladung verwenden, die einen Schlüssel und einen Wert akzeptiert und nicht die, die einen Schlüssel und einen Delegaten akzeptiert.

Um die Delegate-Version zu verwenden, wechseln Sie den Code wie folgt

string val = _cache.GetOrAdd(key, CacheValueFactory);

41
2017-12-09 16:03



Wenn Sie etwas kompliziertere Szenarien behandeln möchten, zum Beispiel, wenn der Parameter nicht mit dem Schlüssel übereinstimmt, könnten Sie ein Lambda verwenden.

        var keyStr = string.Format("Something_{0}", key);
        string val = _cache.GetOrAdd(keyStr,_ => CacheValueFactory(key));

3
2017-10-19 17:01