C
C#2y ago
LukeZurg22

Minor Error Handling ; TryGetValue returning null [Answered]

I have a method that is designed to check through a series of dictionaries and compare the output keys and values. An if-statement is meant to check for any value that could not be gotten with a TryGetValue and instead do something else, but despite that check being there it spits an error exclaiming it could not get a value out to begin with.
20 Replies
LukeZurg22
LukeZurg222y ago
public unsafe void DrawPoliticalMap()
{
FirstLayer.Lock();
var pixels = (uint*)FirstLayer.BackBuffer;

var pixelCount = FirstLayer.PixelWidth * FirstLayer.PixelHeight;

Parallel.For(0, pixelCount, (index) =>
{
var rawPixel = pixels[index];
if (ModData.GetColorsToProvinceIDs().TryGetValue(rawPixel, out var provinceID) &&
ModData.GetProvinces().TryGetValue((uint)provinceID, out var province) &&
ModData.GetTagsToCountryNames().TryGetValue(province.Owner, out var countryName) &&
ModData.GetCountryNamesToColours().TryGetValue(countryName, out var countryColor))
{
pixels[index] = GetRawColor(countryColor);
}
else if
(ModData.GetColorsToProvinceIDs().TryGetValue(rawPixel, out var uncolonizedID)
&& !ModData.GetProvinces().TryGetValue((uint)provinceID, out var provinceFile)
&& ModData.GetTagsToCountryNames().TryGetValue(provinceFile.Owner, out var owner))
//See if actually utilized
{
pixels[index] = GetRawColor(Colors.White);
}
else
{
pixels[index] = GetRawColor(Colors.Black); //Uncolonized
}
});

FirstLayer.Unlock();
SizeReference = FirstLayer;
}
public unsafe void DrawPoliticalMap()
{
FirstLayer.Lock();
var pixels = (uint*)FirstLayer.BackBuffer;

var pixelCount = FirstLayer.PixelWidth * FirstLayer.PixelHeight;

Parallel.For(0, pixelCount, (index) =>
{
var rawPixel = pixels[index];
if (ModData.GetColorsToProvinceIDs().TryGetValue(rawPixel, out var provinceID) &&
ModData.GetProvinces().TryGetValue((uint)provinceID, out var province) &&
ModData.GetTagsToCountryNames().TryGetValue(province.Owner, out var countryName) &&
ModData.GetCountryNamesToColours().TryGetValue(countryName, out var countryColor))
{
pixels[index] = GetRawColor(countryColor);
}
else if
(ModData.GetColorsToProvinceIDs().TryGetValue(rawPixel, out var uncolonizedID)
&& !ModData.GetProvinces().TryGetValue((uint)provinceID, out var provinceFile)
&& ModData.GetTagsToCountryNames().TryGetValue(provinceFile.Owner, out var owner))
//See if actually utilized
{
pixels[index] = GetRawColor(Colors.White);
}
else
{
pixels[index] = GetRawColor(Colors.Black); //Uncolonized
}
});

FirstLayer.Unlock();
SizeReference = FirstLayer;
}
LukeZurg22
LukeZurg222y ago
LukeZurg22
LukeZurg222y ago
It stems from province.Owner being null, but this kind of check should intentionally skip over to other code given this case.
mtreit
mtreit2y ago
Well, you can't pass null to TryGetValue.
LukeZurg22
LukeZurg222y ago
Of course If null is being sent into TryGetValue, i'd imagine that since it is embedded in an if statement, it would simply return "false" for the statement itself and continue on.
mtreit
mtreit2y ago
No, the fact that it throws an exception and you do not have an exception handler means as soon as the exception happens it will stop executing anything else (unless you have a finally block) and pass that exception back down the call stack.
LukeZurg22
LukeZurg222y ago
Schise
mtreit
mtreit2y ago
For those cases where you know it could be null, probably better to call those separately and then insert into your if checks.
bool foundOwner = false;

if (provinceFile?.Owner != null)
{
foundOwner = ModData.GetTagsToCountryNames().TryGetValue(provinceFile.Owner, out var owner));
}

// other code
else if
(ModData.GetColorsToProvinceIDs().TryGetValue(rawPixel, out var uncolonizedID)
&& !ModData.GetProvinces().TryGetValue((uint)provinceID, out var provinceFile)
&& foundOwner)
//See if actually utilized
{
pixels[index] = GetRawColor(Colors.White);
}
bool foundOwner = false;

if (provinceFile?.Owner != null)
{
foundOwner = ModData.GetTagsToCountryNames().TryGetValue(provinceFile.Owner, out var owner));
}

// other code
else if
(ModData.GetColorsToProvinceIDs().TryGetValue(rawPixel, out var uncolonizedID)
&& !ModData.GetProvinces().TryGetValue((uint)provinceID, out var provinceFile)
&& foundOwner)
//See if actually utilized
{
pixels[index] = GetRawColor(Colors.White);
}
Oops, forgot the null check at first. Fixed it. Another option would be to use some sentinel value that you know will not be in the dictionary and inline that, like:
something.TryGetValue((someKey == null ? keyThatForSureDoesNotExist : someKey), out var provinceFile)
something.TryGetValue((someKey == null ? keyThatForSureDoesNotExist : someKey), out var provinceFile)
I dislike that though as it's brittle and harder to read. And could be disastrous if you are wrong that the sentinel key you use will never exist.
LukeZurg22
LukeZurg222y ago
The key most assuredly exists elsewhere, and I'll see what I can do. Frankly a lot of this is old code I made and with help, so it's bastardized to all hell and it'll take a moment to see if it works.
mtreit
mtreit2y ago
What I meant was using something like -1 or int.MinValue if for instance your dictionary contained integers and you know they are only ever positive values. Or for string keys you could just use a fixed GUID like "25d0140e-fd49-4508-ab15-1931d31a5a58" that you know will never be a valid key.
LukeZurg22
LukeZurg222y ago
I don't understand. Certainly the ID's in the dictionaries are only positive, and relatively small. But after that, you've lost me.
mtreit
mtreit2y ago
What type are the keys? Like what is the type of Owner?
LukeZurg22
LukeZurg222y ago
string 1 second
LukeZurg22
LukeZurg222y ago
LukeZurg22
LukeZurg222y ago
These are the get methods for those dictionaries; same types as the return.
mtreit
mtreit2y ago
I was just saying that if you wanted to avoid the null argument exception you could have done something like:
&& ModData.GetTagsToCountryNames().TryGetValue((provinceFile.Owner == null ? "dummy_value" : provideFile.Owner), out var owner))
&& ModData.GetTagsToCountryNames().TryGetValue((provinceFile.Owner == null ? "dummy_value" : provideFile.Owner), out var owner))
That's all That way you pass some non-null value to the dictionary and it will be happy and not throw an exception. Again, I don't think this is the most readable way to do it but was just giving it as an option.
LukeZurg22
LukeZurg222y ago
I understand, no worries. Looks very useful, but sadly the nature of the program won't allow me to pass something to just make it 'happy'; if only!
mtreit
mtreit2y ago
No, I mean, if the key is null it will just cause that conditional check to fail which is what you said originally you had hoped the behavior would be in the case of null. You said this:
If null is being sent into TryGetValue, i'd imagine that since it is embedded in an if statement, it would simply return "false" for the statement itself and continue on.
What I suggested would achieve the same thing you seemed to be asking for. Although all of this discussion could be avoided if Owner being null was not possible in the first place.
LukeZurg22
LukeZurg222y ago
Aye. I've got it sorted and it runs perfectly regardless, thank you. The above code you suggested worked relatively well, with some tweaking.
Accord
Accord2y ago
✅ This post has been marked as answered!