Подтвердить что ты не робот

ConcurrentDictionary.GetOrAdd всегда выполняет метод делегирования

Я замечаю, что GetOrAdd() всегда выполняет делегат factory, даже если это значение существует в словаре. Например:

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

При первом вызове GetValueFromCache ( "A" ) кеш пуст и добавляется A: Apple. Вступив в отладчик, я заметил, что во втором и третьем вызовах GetValueFromCache ( "A" ) всегда выполняется метод CacheValueFactory(). Ожидается ли это? Я бы подумал, что метод делегата не будет выполняться, если ключ существует в словаре.

4b9b3361

Ответ 1

Причина, по которой вы видите это, заключается в том, что вы не передаете CacheValueFactory в качестве делегата, а вместо этого быстро вычисляете функцию и передаете результирующее значение. Это заставляет использовать перегрузку, которая принимает ключ и значение, а не тот, который принимает ключ и делегирует.

Чтобы использовать версию делегата, переведите код в следующий

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

Ответ 2

Если вы хотите обрабатывать несколько более сложные сценарии, например, когда параметр не соответствует ключу, вы можете использовать lambda.

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