2010-12-09 3 views
22

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

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(). Ожидается ли это? Я бы подумал, что метод делегата не будет выполняться, если ключ существует в словаре.

ответ

41

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

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

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

Ooops. Вы правы :) – Bullines 2010-12-09 16:05:40

2

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

 var keyStr = string.Format("Something_{0}", key); 
     string val = _cache.GetOrAdd(keyStr,_ => CacheValueFactory(key)); 
Смежные вопросы