TryGetValue Evaluating to False Even When Key is Present - c#

This question is basically the same as this one, although the answer to that person's problem turned out to be a simple trailing space.
My issue is that I'm retrieving data from a web API as dictionary and then trying get the values out of it. I'm using TryGetValue because not every item in the dictionary will necessarily contain every key. For some reason, whilst I can get the value of one key with no problems at all when it's present, for another key TryGetValue always evaluates to false and therefore doesn't return the value, even though I can see in debug that the key is present.
So, this block always retrieves the value of the "System.Description" key if it's present:
string descriptionValue = "";
if (workItem.Fields.TryGetValue("System.Description", out descriptionValue))
{
feature.Description = descriptionValue;
}
However, this almost identical block NEVER retrieves the value of the "CustomScrum.RoadmapGroup" key:
int RoadmapGroupValue = 0;
if (workItem.Fields.TryGetValue("CustomScrum.RoadmapGroup", out RoadmapGroupValue))
{
feature.RoadmapGroup = RoadmapGroupValue;
}
As you can see in this screenshot, the dictionary DOES contain a key with a name exactly matching my TryGetValue statement:
If I put a breakpoint on the code which should be run if the TryGetValue statement evaluates to true (feature.Description = descriptionValue;) it never gets hit.
The feature.RoadmapGroup variable gets set to 0 for every item in the dictionary.
I've been staring at this for the last two hours at least and I can't see what I'm doing wrong.

Here's a scenario where your cast goes wrong.
private void foo()
{
Dictionary<string, object> dict = new Dictionary<string, object>();
object obj = new object();
obj = "1";
dict.Add("CustomScrum.RoadmapGroup", obj);
object val;
var result = dict.TryGetValue("CustomScrum.RoadmapGroup", out val);
int value = (int)val;
}
TryGetValue() returns true, but the last line (the cast), throws System.InvalidCastException: 'Specified cast is not valid.', although if you use a breakpoint to see the dictionary content it looks like you have something that can be converted to an int. See below:
So I believe that when you add the value to the dictionary, you're not really adding an int but something that looks like an int.
EDIT
I just replaced int value = (int)val; with int value = Convert.ToInt32(val); which converts the value just fine. So you might want to try to use that and see if that works as well.

Are you sure that this "CustomScrum.RoadmapGroup" key is a string? If yes, then make sure that it doesn't contain any special unreadable character. You can just copy this value while debugging, put it in Watch window and check length/bytes representation, then do the same for hand-written string with the same content.

Related

TargetParameterCountException when iteratively retrieving value out of reflexive properties of a string

Some context first :
I was writing a reusable "null tester" method that will be used to check if any variable of an object has a null or empty value. the goal is that the method can take an Object and use reflexion to check the value of each property.
Everything worked until I added a List<string> to a class that is being checked.
While adding List<string> raised the TargetParameterCountException other primitive types didn't. The only other time I managed to reproduce this error is when I passed directly a string.
I managed to boil down this problem to that bit of code :
string toCheck = "foo";
var elementProperties = toCheck.GetType().GetProperties();
foreach (PropertyInfo property in elementProperties)
{
var elementValue = property.GetValue(toCheck);
//Check if "toCheck" is null or empty here
}
elementProperties has two Values
An Int32 Length
A Char Chars[Int32]
My understanding would be that the first represent the length and the second the content of the string. But when the code tries to "GetValue()" the second property it raises a TargetParameterCountException.
Does someone know why it would do that ?
since I was trying to access a char array I needed to specify the index of which char I want to retrieve.
using :
property.GetValue(toCheck, new object[] {index})

Dictionary internal hashcode [duplicate]

I understand that it is not advisable to use "mutable" objects (objects whose GetHashCode() method can return different results while they being used as keys in a Dictionary).
Below is my understanding of how a dictionary, which is implemented as a hash table, works:
When I am adding new key, for example dict.Add(m1, "initially here was m1 object");, dict calculates the hashcode of m1 using the GetHashCode() method. Then it does some internal calculations and finally puts this object into some position of its internal array.
When I am using the key index to get the value, for example dict[m1], dict calculates the hashcode again. Then it does some internal calculations, and it gives me an object which is located at the calculated position inside of its internal array.
But I think there is an error which I can't find.
So lets assume that I have this code:
class MutableObject
{
Int32 m_value;
public MutableObject(Int32 value)
{
m_value = value;
}
public void Mutate(Int32 value)
{
m_value = value;
}
public override int GetHashCode()
{
return m_value;
}
}
static void Main(string[] args)
{
MutableObject m1 = new MutableObject(1);
MutableObject m2 = new MutableObject(2);
var dict = new Dictionary<MutableObject, String>();
dict.Add(m1, "initially here was m1 object");
dict.Add(m2, "initially here was m2 object");
Console.WriteLine("Before mutation:");
Console.WriteLine("dict[m1] = " + dict[m1]);
Console.WriteLine("dict[m2] = " + dict[m2]);
m1.Mutate(2);
m2.Mutate(1);
Console.WriteLine("After mutation:");
Console.WriteLine("dict[m1] = " + dict[m1]);
Console.WriteLine("dict[m2] = " + dict[m2]);
Console.ReadKey(true);
}
When I call Mutate methods, keys are swapped. So I thought it will give swapped results. But actually this line: Console.WriteLine("dict[m1] = " + dict[m1]); throws KeyNotFoundException, and I can't understand why. Obviously I am missing something here...
How .NET Dictionary implementation works with mutable objects
It doesn't. The documentation for Dictionary states:
As long as an object is used as a key in the Dictionary<TKey, TValue>, it must not change in any way that affects its hash value.
Since you're changing the object while it's in the Dictionary it will not work.
As for why, it's not too hard to see. We put in an object. Let's assume that the hash code is 1. We put the object in the 1 bucket of our hash table. Now the object is mutated from outside the Dictionary so that it's value (and hash code) is 2. Now when someone gives that object to the dictionary's indexer it gets the hash code, see's that it's 2, and looks in the 2 bucket. That bucket is empty, so it says, "sorry, no element".
Now let's assume that a new object is created with a value and hash of 1. It's passed to the Dictionary, who sees that the hash is 1. It looks in the 1 bucket and finds that there is indeed an item at that index. It now uses Equals to determine if the objects are in fact equal (or if this is just a hash collision).
Now, in your case, it will fail here because you don't override Equals, you're using the default implementation which compares references, and since this is a different object it won't have the same reference. However, even if you changed it to compare the values, *the first object was mutated to have a value of 2, not 1, so it won't match anyway. Others have suggested fixing this Equals method, and you really should do that, but it still won't fix your problem.
Once the object is mutated the only way of finding it is if it just so happens that the mutated value is a hash collision (which is possible, but unlikely). If it's not, then anything that is equal according to Equals will never know to check the right bucket, and anything that checks the right bucket won't be equal according to Equals.
The quote I mentioned at the start isn't just a best practice. It's not just unexpected or weird or unperformant to mutate items in a dictionary. It just doesn't work.
Now, if the object is mutable but isn't mutated while it's in the dictionary then that's fine. It may be a bit odd, and that's a case people may say is bad practice, even if it works.
It's not enough to do a dictionary lookup to have the same hash code. Since hash collisions are possible, the key must also be equal the index being looked up.
Your MutableObject class doesn't override Equals(object). Hence reference equality is used (inherited from base class System.Object).
The Dictionary<,> first (quickly) finds any keys with the correct hash code. It then examines each of those candidate keys to check if one of them Equals the key it is searching for.
Therefore Equals(object) and GetHashCode() should be overridden together. You would get a warning from the compiler if you overrode only one of them.
As soon as the hash code of a key mutates while the key is in the Dictionary<,>, that key will (probably) be misplaced inside the Dictionary<,>, be in the wrong "bucket", and hence be lost. It will not be found, because search for it will always take place in a bucket where it isn't located.
In this example, the key gets lost, and therefore can be added again:
var dict = new Dictionary<MutableObject, string>();
var m = new MutableObject(1);
dict.Add(m, "Hello");
m.Mutate(2);
dict.Add(m, "world");
foreach (var p in dict)
Console.WriteLine(p);
var otherDict = new Dictionary<MutableObject, string>(dict); // throws
I have actually seen an exception like that, during initializing of one Dictionary<,> with the items from an existing Dictionary<,> (both using the default EqualityComparer<> for the key type).

C# SortedDictionary in-place update [duplicate]

This question already has answers here:
Error: "Cannot modify the return value" c#
(8 answers)
Closed 8 years ago.
I have a SortedDictionary defined as:
public SortedDictionary<DateTime,RosterLine> RosterLines = new SortedDictionary<DateTime,RosterLine>();
RosterLine itself is a simple struct:
struct RosterLine {
public string RosCd;
public string ActCd;
public double Hrs;
}
I can .Add(dt, rosterLine) no problems, and iterate through the dictionary fine too.
My problem is trying to update the RosterLine values given a specified date eg.
DateTime currDt = new DateTime(2013,12,02);
RosterLines[currDt].ActCd = "SO"; // error here
It tells me: Cannot modify the return value (dictionary def here) because it is not a variable. My goal is to do this with an iterating loop (which I thought might be the problem), but it won't work outside the loop on its own either (as above).
My question is: how do I update a SortedDictionary with a given key (date)?
The reason for the error message is that RosterLine is a struct and by that a value type. The error I get in ideone is:
Cannot modify a value type return value of
`System.Collections.Generic.SortedDictionary.this[System.DateTime]'.
Consider storing the value in a temporary variable
For value types, the dictionary stores a copy of the value and not a reference to the object on the heap. Also, when retrieving the value (as in dict[DateTime.Today]), it is copied again. Therefore, changing a property in the way you do in your sample only works on the copy of the value type. The compiler prevents misunderstandings by the error message - if it wouldn't one would wonder why the value in the dict has not been changed.
var dict = new SortedDictionary<DateTime, RosterLine>();
dict.Add(DateTime.Today, new RosterLine());
// Does not work as RosterLine is a value type
dict[DateTime.Today].ActCd = "SO";
// Works, but means a lot of copying
var temp = dict[DateTime.Today];
temp.ActCd = "SO";
dict[DateTime.Today] = temp;
In order to solve this, you could make RosterLine a class or you can work with temp variables as the error message suggests.

How is the C# Dictionary used this way in C# in depth 2nd Edition?

I have come across the following code in C# in Depth 2nd Edition by Jon Skeet and I don't understand how it works.
Dictionary<string,int> frequencies;
frequencies = new Dictionary<string,int>();
string[] words = Regex.Split(text, #"\W+");
foreach (string word in words)
{
if (frequencies.ContainsKey(word))
{
frequencies[word]++;
}
else
{
frequencies[word] = 1;
}
}
Specifically how does the "word" key get added to the dictionary? As I see it, a new dictionary is created called frequencies, it is empty. There is then a method to split a string called text into an array of string using Regex.Split. So far all good. Next there is a foreach loop which loops through the array, but the next part trips me up, it is checking if frequencies contains the particular word, if it does then increase the value of it by 1 or if it doesn't yet have a value set it to 1. But how does the dictionary get populated with the "word" key in the first place to allow it to be checked?
It looks to happen in this line
frequencies[word] = 1;
But I can't find a reference anywhere that says specifying a dictionary object followed by square brackets and an assignment to a value also populates the key. I thought you needed to use the add method of the dictionary instance or do so when initializing the dictionary.
If I am correct what is the name of this action?
frequencies[word] = 1;
is the same as calling
frequencies.Add(word, 1);
if the key word does not already exist. Otherwise you override the value.
When you call [something] on a dictionary you get a value by key something. The same goes for setting. When setting a value you can call dictionary[key] = value.
The function used is the [] operator (brackets operator).
I dove into the Object Browser and found this about the [] operator of the generic dictionary:
public TValue this[TKey key] { get; set; }
Member of System.Collections.Generic.Dictionary<TKey, TValue>
Summary: Gets or sets the value associated with the specified key.
Parameters: key: The key of the value to get or set.
Return Values: The value associated with the specified key. If the
specified key is not found, a get operation throws a
System.Collections.Generic.KeyNotFoundException, and a set operation
creates a new element with the specified key.
Exceptions: System.ArgumentNullException: key is null.
System.Collections.Generic.KeyNotFoundException: The property is
retrieved and key does not exist in the collection.

c# Object obj's value is {}. What is "{}"?

I'm using some old code that runs a sql query as a reference.
At some point, it gets to something like:
sqlDataAdapter.Fill(dataSet);
DataRow dataRow = dataSet.Tables[0].Rows[0];
Object obj = dataRow[fieldName];
The old code does:
string output;
if (!string.IsNullOrEmpty(obj.ToString())) { output = obj.ToString(); }
else { output = "Not Available"; }
I changed them to:
output = obj as string ?? "Not Available"
But sometimes, it broke. As I suspected, it was happening breaking when the entry was an int. Casting as an int in those cases solved that problem.
Then another problem arose when there was no entry for obj[fieldName] of type int. When I stepped through the debugger, I was surprised to find that obj wasn't null. In VS, mousing over revealed it had a value {}.
What the heck is {}? How do I make a boolean test of it?
(In the old code, it appears .ToString() returns "" in this case and works as expected.)
{ and } are opening and closing braces and symbolic of the start and finish of an object. Hence an empty object with no special properties is depicted in shorthand as {}. The debugger uses this notation to help you visually distinguish between an empty object, an empty string and null.
If you hover over obj[fieldName] and there is no entry for fieldName, the debugger won't care about that, it'll show the value of obj. You'll have to use the immediate window or a watch/quickwatch. The debugger will only see you hovering over obj and assume you're referring to the array itself, not the contents of the array at the specified index.
In case anyone comes across again this problem.
Solution if val object is shown {} in debug mode
// Check if its not null or empty
if (!IsNullOrEmpty(val.ToString().ToArray()))
{
// Do something with val
dt.Rows.Add(val);
}
public static bool IsNullOrEmpty<T>(T[] array)
{
return array == null || array.Length == 0;
}

Categories