提问人:Peter O Brien 提问时间:12/26/2022 最后编辑:Peter O Brien 更新时间:1/3/2023 访问量:83
使用具有引用类型字典的 By Ref 时出现意外行为
Unexpected behavior using By Ref with Reference type Dictionary
问:
使用 Dictionary 类型并按引用传递时遇到意外行为。 在嵌套调用中,对底层基础字典的引用似乎丢失或被替换。 所有子方法调用都按 ref 传递字典。
public void Main() {
// Get Dictionary and fill if empty - Type 1 Dictionary
Dictionary<string, string> dictStored = DictionaryFetch(1);
// Pull from previously filled and stored static dictionary
dictStored = DictionaryFetch(1);
}
我的理解是,我正在传递本地类型的地址引用(它本身就是一个引用类型对象 - Dictionary)。
如果在子方法上分配了字典,则该操作将在父字典上发生(这意味着它是相同的对象,相同的内存地址引用)。
内 ,如果字典为空,需要创建,则最后的开关。不应要求将大小写分配给静态字典。我想删除对根静态字典的最终重新分配。DictionaryFetch()
// Method to find and return the correct Dictionary by Type.
void DictionaryFetch(int DictType)
{
Dictionary<string, string> localDict = new();
// Retrieve Dict pass by reference
// localDict will contain static dictA or dictB contents
DictionaryFetchStatic(dictType, ref localDict);
// Check dictionary, create if empty
if (localDict.Count == 0)
{
// Method to populate localDict with entries.
CreateDictionary(ref localDict);
// Here is the gotcha, the static dictA or dictB is still empty,
// but localDict is populated - hence the need for the following switch statement
switch(dictType)
{
case 1:
dictA = localDict;
break;
case 2:
dictB = localDict;
break;
};
}
return localDict;
}
我错过了什么?为什么在最终切换之前没有填充 dictA..?DictionaryFetch()
static Dictionary<string, string> dictA = new();
static Dictionary<string, string> dictB = new();
void DictionaryFetchStatic(int dictType, ref Dictionary<string, string> dictRequester)
{
switch(dictType)
{
case 1:
dictRequester = dictA;
break;
case 2:
dictRequester = dictB;
break;
};
}
void CreateDictionary(ref Dictionary<string, string> dictRequester)
{
// Just an example of creating a dictionary using DbContext, its generating a new Dict in response.
dictRequester = _context.owner.Where(x => x.type == 'abc')
.ToDictionary(o => o.key, o => o.value);
}
答:
0赞
WBuck
12/26/2022
#1
您正在 中分配新的引用(地址)。您的引用将不再指向 。FillDictMethod
dictA
如果你想让它按预期工作,你需要改变变量,而不仅仅是将其重新赋值到其他地方。ref
static void FillDictMethod( ref Dictionary<string, string> dictRequester )
{
// Add the values to the dictionary pointed to
// by dictRequester.
dictRequester.TryAdd( "Test", "Test" );
}
评论
0赞
Peter O Brien
12/27/2022
感谢@WBuck,在我的实际场景中,字典由 DbContext 填充,因此它将产生一个新的引用类型字典。我想我已经在我的答案中确定了处理这个问题的最佳方法——但我对改进持开放态度。C# 中类型的“幕后”发生的事情有时可能是暗示性的。
0赞
WBuck
12/27/2022
@PeterOBrien同样的事情也会发生。C++
0赞
Peter O Brien
12/27/2022
#2
感谢您提供有用的回复提示。 在我的实际场景中,fill 方法将使用 DbContext 并生成一个新的非常大的字典。
解决方案是避免使用本地范围定义的字典 var,而是在 DictControllerMethod() 中定义一个 ref 字典。这避免了我的问题中报告的 [指针指向指针] 问题 - 仅使用并传递指向根字典的单个指针。
它使用本地定义的字典变量,这会导致不必要的附加层。使用 reference-type[dictionary] by value 增加了混淆。
public void Main() {
int dictionaryType = 1;
// Get Dictionary and fill if empty - Type 1 Dictionary
Dictionary<string, string> dictStored = DictionaryFetch(dictionaryType);
// Pull from previously filled and stored static dictionary
dictStored = DictionaryFetch(dictionaryType);
}
方法:
static Dictionary<string, string> dictA = new();
static Dictionary<string, string> dictB = new();
ref Dictionary<string, string> DictionaryFetchStatic(int dictionaryType)
{
switch(dictionaryType)
{
case 1:
return dictA;
case 2:
return dictB;
};
}
// Method to find and return the correct Dictionary by Type.
Dictionary<string, string> DictionaryFetch(int dictionaryType)
{
// localDict will point to static dictA or dictB Dictionary reference type.
ref Dictionary<string, string> localDict = ref DictionaryFetchStatic(dictionaryType);
// Check dict, create if empty
if (localDict.Count == 0)
{
// Method to fill localDict with entries.
CreateDictionary(ref localDict);
}
return localDict;
}
void CreateDictionary(ref Dictionary<string, string> dictRequester)
{
// Just an example of filling a dictionary using DbContext, its generating a new Dict in response.
dictRequester = _context.owner.Where(x => x.type == 'abc')
.ToDictionary(o => o.key, o => o.value);
}
评论
FillDictMethod
dictA