ConcurrentDictionary.GetOrAdd始终执行委托方法

Bul*_*nes 28 c# multithreading .net-4.0

我注意到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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在第一次调用GetValueFromCache("A")时,缓存为空,并添加A:Apple.进入调试器时,我注意到在第二次和第三次调用GetValueFromCache("A")时,CacheValueFactory()方法总是执行.这是预期的吗?如果密钥存在于字典中,我会认为委托方法不会执行.

Jar*_*Par 46

你看到这个的原因是你没有CacheValueFactory作为委托传递,而是迅速评估函数并传递结果值.这会导致您使用接受键和值的重载,而不是接受键和委托的重载.

要使用委托版本,请将代码切换为以下内容

string val = _cache.GetOrAdd(key, CacheValueFactory);
Run Code Online (Sandbox Code Playgroud)


JNa*_*ppi 8

如果要处理稍微复杂的场景,例如,当参数与键不匹配时,可以使用lambda.

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