[Mono-bugs] [Bug 444768] New: Dictionary<K, V> cast as ICollection<K, V> doesn' t have correct behavior for Contains and Remove

bugzilla_noreply at novell.com bugzilla_noreply at novell.com
Thu Nov 13 14:05:54 EST 2008


https://bugzilla.novell.com/show_bug.cgi?id=444768


           Summary: Dictionary<K,V> cast as ICollection<K,V> doesn't have
                    correct behavior for Contains and Remove
           Product: Mono: Class Libraries
           Version: 1.9
          Platform: Other
        OS/Version: Other
            Status: NEW
          Severity: Normal
          Priority: P5 - None
         Component: Sys.Core
        AssignedTo: jbevain at novell.com
        ReportedBy: jonbnews at hotmail.com
         QAContact: mono-bugs at lists.ximian.com
          Found By: ---


The Mono Dictionary<TKey, TValue> class behaves differently than the .NET class
for it's implementation of ICollection.Contains and ICollection.Remove. 

The Dictionary implements ICollection as a collection of KeyValuePair<TKey,
TValue> elements. The argument to ICollection.Contains and ICollection.Remove
is a KeyValuePair<TKey, TValue>. In order to determine if the given
KeyValuePair instance exists (for the contains method), the .NET version
attempts to see if the key exists in the dictionary, and if so, if the value
corresponding to that key is equal to the one in the key value pair. Bascially,
both the key *and the value* have to match in order for Contains to be true. 
Same goes for Remove. The element will only be removed if both the key and
value match. 

In Mono, only the key has to match in order for an item to return true for
Contains and for Remove to remove the element. I believe the .NET version is
correct. When you're dealing with an ICollection interface, the collection
should behave like any collection (such as a list) would with respect to
Contains/Removes and the collection entities (e.g. KeyValuePair) must match
exactly, not just a piece of the entity.

(Remember, this is not for regular dictionary functionality like ContainsKey
and Remove that only works based on the key. This is when the dictionary is
cast to an ICollection and the Contains and Remove are called on that
collection interface).

Here's an example.

Dictionary<string, int> dict = new Dictionary<string, int>();
dict.Add("foo", 1);
ICollection<KeyValuePair<string, int>> col = (ICollection<KeyValuePair<string,
int>) dict;

// Create a key value pair that doesn't match on the value.
KeyValuePair<string, int> match = new KeyValuePair<string, int>("foo", 2);

if (col.Contains(match))
{
   Console.Out.WriteLine("The collection contains the key value pair");
}

I would expect this to not output anything.  It's obvious that the collection
does not contain the specified KeyValuePair, since that value is not in the
dictionary.  Remember, this is from the point of view of an ICollection, which
shouldn't matter what the underlying datastructure is.  Imagine if this was a
list of KeyValuePairs.  I would expect the same behavior whether the
ICollection is for a list of KeyValuePairs or for a dictionary.

The problem is in Dictionary.cs in this method:

                bool ICollection<KeyValuePair<TKey, TValue>>.Contains
(KeyValuePair<TKey, TValue> keyValuePair)
                {
                        return this.ContainsKey (keyValuePair.Key);
                }

It's just checking the key, which I believe is incorrect (and at any rate, is
not the same behavior as .NET).

The same problem goes for the ICollection.Remove method.  It's implemented like
this:

                bool ICollection<KeyValuePair<TKey, TValue>>.Remove
(KeyValuePair<TKey, TValue> keyValuePair)
                {
                        return Remove (keyValuePair.Key);
                }

It just removes the key.  However, from the point of view of ICollection, and
entry in the collection should only be removed if it matches the entire entry,
which is a KeyValuePair.

Here's an example:


Dictionary<string, int> dict = new Dictionary<string, int>();
dict.Add("foo", 1);
ICollection<KeyValuePair<string, int>> col = (ICollection<KeyValuePair<string,
int>) dict;

// Create a key value pair that doesn't match on the value.
KeyValuePair<string, int> match = new KeyValuePair<string, int>("foo", 2);

col.Remove(match);
if (dict.Count == 0)
{
   Console.Out.WriteLine("Item was removed");
}

Again, I would expect no output, because the given item (the KeyValuePair)
doesn't exist in the collection, so it shouldn't be removed.  (Again, this is
from the point of view of an ICollection, irregardless of the underlying data
structure).


-- 
Configure bugmail: https://bugzilla.novell.com/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.


More information about the mono-bugs mailing list