简体   繁体   中英

Collection as key in Dictionary

I have a dictionary like this:

var dic = Dictionary<Collection<MyObject>, string>

Then I add an entry like this:

dic.Add(myObjColl, "1");

where myObjColl contains a single entry

On the second run I try to add another entry to dic where myObjColl has two entries (one of them the same as the one in the first run) and I get an exception that the key already exists.

What am I missing here? I expect the dictionary key to be a collection and surely two collections with different number of entries cannot be identical.

EDIT: What happened was that myObjColl was initialized outside a foreach and during the second iteration updated. So what I thought was a NEW collection with two entries was actually the old one entry collection with an additional entry added.

To elaborate a bit on my issue:

I have a collection of product row objects. Each with a product identification object consisting of a collection of key value pairs:

Collection<ProductKeyValuePair> productIdentification;
myProductRow.ProductIdentification = productIdentification;

I then have to construct another collection of ProductKeyValuePairs defining the "owner" of each product row object (one product row object can have multiple owners) and I need to add each owner to the correspoding procuct row object(s). A traditional many to many where the common key is a collection of KeyValuePairs.

Hard to explain but it's really down to legacy data returned from old systems running on a mainframe and most likely stored in a hierarchical database of some sort :-/

Keys in dictionaries are expected to be immutable while they are performing their role as a key. If you do anything to change the value of GetHashCode() or Equals(object) you will get undefined behavior.

(also if Collection does not implement GetHashCode() and Equals(object) to use the members it contains it will just do a comparison by reference to the container object itself)

It's not examining the contents of the collection.

It's simply using myObjColl (by ref) as the key.

Note: it is very unusual to have a collection as key. Keys are usually strings (or integers).

To have reference type like collection to be key in dictionary you usually need to pass custom comparer ( IEqualityComparer<TKey> ) to constructor of dictionary. Otherwise default Equals / GetHashCode implementation of the class is used which normally does not have value semantic (Ie string is sample of reference type that behaves like value).

Overly simplified comparer for collection (no null checks, only compares count) and usage below:

class ListSameByCount<T> : EqualityComparer<List<T>>
{

  public override bool Equals(List<T> b1, List<T> b2)
  {
    return b1.Count() == b2.Count();
  }

  public override int GetHashCode(List<T> b1)
  {
    return b1.Count().GetHashCode();
  }
}

var dictionary = new Dictionary<List<int>, int>(new ListSameByCount<int>());

Note: collections often bad candidates for keys in dictionary because they can be mutated (items added/removed/changed) and as result hash code would change and dictionary will not be able to find the key.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM