c# - 并发字典中的 valueFactory

标签 c# delegates func concurrentdictionary

我正在编写一个 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 构造函数。我怀疑这是因为我传递了委托(delegate) valueFactory 而不是函数调用 valueFactory()到 GetorAdd 方法。 我想知道在幕后发生的事情是否有详细的解释,我也不明白为什么如果我的 Func 定义不是 Func<int, Class1 ,我不能不将 valueFactory 作为委托(delegate)传递(与字典定义相同)

谢谢。

最佳答案

当你这样做时:

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

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

相反,当你这样做时:

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

...您实际上使用的是方法 GetOrAdd 的不同重载,您可以在其中传递对委托(delegate) valueFactory 的引用无需自己调用它。 GetOrAdd()然后方法决定是否需要调用 valueFactory或不基于是否在字典中找到该键。

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

Adds a key/value pair to the ConcurrentDictionary<TKey, TValue> by using the specified function, if the key does not already exist.

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


但是,请注意传入valueFactory作为 GetOrAdd 的委托(delegate)不保证它不会被调用两次。在多线程场景中尤其如此。请注意 ConcurrentDictionary.GetOrAdd Method (TKey, Func) 上的文档内容还提到了这一点:

If you call GetOrAdd simultaneously on different threads, addValueFactory may be called multiple times, but its key/value pair might not be added to the dictionary for every call.

关于c# - 并发字典中的 valueFactory,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32334305/

相关文章:

c# - 将 C# PageAsyncTask() 转换为 VB.Net 等效项时出现问题

c# - 如何创建子对象的 Expression.Property

go - "undefined"函数在另一个文件中声明?

c# - 在 C# 中构建动态正则表达式

c# - Visual Studio 2017 单元测试未运行

c# - 使用 Kinect 在 InkCanvas WPF 中绘制平滑线条

c - 如何标准化数据并清除数组

c# - SQLite 加入嵌入式数据库表

C# 内部委托(delegate)和公共(public)事件

swift - NSTouchBar 集成不调用