dictionary.TryGetValue vs FirstOrDefault

According to MSDN documentation, a Tuple objects Equals method will use the values of the two Tuple objects.

Why does the following not produce the same result:

[Test]
public void TestTupleWithDictionary() 
{
    Dictionary<Tuple<string, string>, string> values = new Dictionary<Tuple<string, string>, string>();

    values.Add(new Tuple<string, string>("1", "1"), "Item 1");
    values.Add(new Tuple<string, string>("1", "2"), "Item 2");

    Assert.IsNotNull(values.FirstOrDefault(x => x.Key == new Tuple<string, string>("1", "2")));

    string value;
    values.TryGetValue(new Tuple<string, string>("1", "2"), out value);

    Assert.IsNotNullOrEmpty(value);
}

Why does values.FirstOrDefault(x => x.Key == new Tuple<string, string>("1", "2")) return null where as values.TryGetValue(new Tuple<string, string>("1", "2"), out value); finds the correct key and returns the value?

Jon Skeet
people
quotationmark

You're using ==, which isn't overloaded for Tuple<,>, so it's using a reference identity check... and as you've constructed a new tuple, that will never be true.

This would be correct, but undesirable:

// Don't do this!
values.FirstOrDefault(x => new Tuple<string, string>("1", "2").Equals(x.Key))

That would:

  • Create a new tuple on each iteration
  • Have to look through every entry until it found a matching one, which is an O(N) operation... compared with the normally-O(1) operation of a dictionary lookup

people

See more on this question at Stackoverflow