Experienced an unexpected behavior when using Dictionary type and passing by reference. Within a nested call, the reference to the underlaying base dictionary seems to be lost or replaced. All child method calls are passing the dictionary by 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);
}
My understanding is that I am passing the address reference of the local type (which itself is a reference type object - Dictionary).
If a dictionary is assigned on the child method that action occurs on the parent dictionary (meaning its the same object, same memory address ref).
Within DictionaryFetch(), if the dictionary is empty and needs to be created, the final switch..case assignment to the static dictionary should not be required. I would like to remove this final reassignment to the root static dictionary.
// 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;
}
What am I missing? Why is the dictA not populated before the final switch..case statement in 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);
}
Thanks for helpful response tips. In my real-world scenario the fill method will use a DbContext and will generate a new very large dictionary.
The solution is to avoid use of local scope defined dictionary var, instead define a ref dictionary within DictControllerMethod(). This avoids the [pointer to a pointer] issue as reported in my question - just using and passing a single pointer to the root dictionary.
Its use of local defined dictionary vars that cause the unnecessary additional layers. The use of a reference-type[dictionary] by value added to the confusion.
Methods: