我正在编写一个 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/