【问题标题】:valueFactory in Concurrent dictionary并发字典中的 valueFactory
【发布时间】:2015-11-26 20:22:43
【问题描述】:

我正在编写一个 winform 程序来测试具有以下类的 C# 并发字典:

public class Class1
{
    public int X = 10;

    public Class1(int x)
    {
        X = x;
        Debug.WriteLine("Class1 Created");
    }
}

及以下按钮代码:

  private void button1_Click(object sender, EventArgs e)
    {
        var dict = new ConcurrentDictionary<int, Class1>();

        Func<Class1> valueFactory = () => 
        {
            Debug.WriteLine("Factory Called");
            return new Class1(5);
        };

        var temp = dict.GetOrAdd(1, valueFactory());
        Debug.WriteLine(temp.X);
        temp.X = 20;

        var temp2 = dict.GetOrAdd(1, valueFactory());
        Debug.WriteLine(temp2.X);
    }

我注意到 valueFactory 方法总是被执行并且 Class1 构造函数被调用了两次,即使在第一个 GetorAdd 方法之后键已经存在于 dict 中。

但是,如果我将 Func 定义更改为

Func<int, Class1> valueFactory = (k) => 
        {
            Debug.WriteLine("Factory Called");
            return new Class1(5);
        };

并像下面这样调用 GetorAdd 方法:

var temp = dict.GetOrAdd(1, valueFactory);

程序以所需的方式工作,因为它在第二次调用中没有调用 Class1 构造函数。我怀疑这是因为我将委托 valueFactory 而不是函数调用 valueFactory() 传递给 GetorAdd 方法。 我想知道是否有关于幕后发生的事情的详细解释,我也不明白为什么如果我的 Func 定义不是Func&lt;int, Class1(与字典)

谢谢。

【问题讨论】:

    标签: c# delegates func concurrentdictionary


    【解决方案1】:

    当你这样做时:

    var temp = dict.GetOrAdd(1, valueFactory());
    ...
    var temp2 = dict.GetOrAdd(1, valueFactory());
    

    您实际上是在调用valueFactory调用dict.GetOrAdd()。所以每次都被调用是正常的。当然,第二次调用valueFactory() 返回的Class1 的新实例最终没有用,但它还是被创建了。

    相反,当你这样做时:

    var temp = dict.GetOrAdd(1, valueFactory);
    ...
    var temp2 = dict.GetOrAdd(1, valueFactory);
    

    ...您实际上正在使用方法GetOrAdd 的不同重载,在该方法中您传递对委托valueFactory 的引用而不自己调用它。然后GetOrAdd() 方法根据是否在字典中找到键来决定是否需要调用valueFactory

    ConcurrentDictionary.GetOrAdd Method (TKey, Func)文档:

    使用指定的函数将键/值对添加到ConcurrentDictionary&lt;TKey, TValue&gt;如果键不存在。

    在这种情况下,它不需要第二次调用它,因为它会在您第二次调用 GetOrAdd() 时找到密钥。


    但是,请注意,将valueFactory 作为代表传递给GetOrAdd 并不能保证它不会被调用两次。在多线程场景中尤其如此。请注意ConcurrentDictionary.GetOrAdd Method (TKey, Func) 上的文档也对此进行了说明:

    如果您在不同线程上同时调用GetOrAddaddValueFactory 可能会被多次调用,但它的键/值对可能不会在每次调用时都添加到字典中。

    【讨论】:

      猜你喜欢
      • 2015-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-24
      相关资源
      最近更新 更多