[Mono-dev] Key matching issue in generic Dictionary [correct message]
Hi all I'm facing a strange behavior affecting System.Collections.Generic.DictionaryTKey,TValue: when I try to search for a key among the dictionary entries using interface members such as ContainsKey(TKey key) or this[TKey key] I receive wrong responses (the key can't be find, whilst it's really there!). I supposed that it could be a problem on the TKey side (where I implemented System.IEquatableTKey), so I put some Console.WriteLine() inside the code to verify. A System.Collections.Generic.Dictionary instance is incapsulated in MyDictionary (an implementation of generic IDictionary), TKey is assigned to Name type, TValue is irrelevant. class Name : IEquatableName { public Name(string value) { ... } public bool Equals(Name obj) { Console.WriteLine(Name.Equals(): this: + this.value + other: + obj.Value); return this.value.Equals(obj.Value); } public string Value { get{return this.value;} } } class MyDictionary : IDictionaryName,Object { protected DictionaryName,Object entries = new DictionaryName,Object(); ... public bool ContainsKey(Name key) { Console.WriteLine(MyDictionary.ContainsKey: key = + key.Value); return this.entries.ContainsKey(key); } public Object this[Name key] { get { try { Console.WriteLine(Dictionary[]: key = + key.Value); return ((Object) this.entries[key]); } catch(Exception e) { Console.WriteLine(Dictionary[]:exception: + e.Message); foreach(KeyValuePairPdfName,Object kv in this.entries) { Console.WriteLine(PdfDictionary[]: pair: key = + kv.Key.Value + equals : + key.Equals(kv.Key)); } return null; } } } ... } Here's the test I made: 1) populate MyDictionary with 3 entry pairs, whose keys are: Name(Info), Name(Root), Name(Size); 2) try to find Name(Encrypt) among MyDictionary keys, invoking MyDictionary.ContainsKey(Name key) method and obtaining such console output: MyDictionary.ContainsKey: key = Encrypt Name.Equals(): this: Encrypt other: Info Name.Equals(): this: Encrypt other: Root 3) as you can see from the previous step, it strangely missed to invoke Name.Equals for the Name(Size) instance (just considered Name(Info) and Name(Root): why? 4) try to get the object related to the Name(Size) key invoking MyDictionary.this[Name key] method and obtaining such console output: Dictionary[]: key = Size Dictionary[]:exception: The given key was not present in the dictionary. Name.Equals(): this: Size other: Info Dictionary[]: pair: key = Info equals : False Name.Equals(): this: Size other: Root Dictionary[]: pair: key = Root equals : False Name.Equals(): this: Size other: Size Dictionary[]: pair: key = Size equals : True 5) as you can see from the previous step, before the exception message there is NO invocation to Name.Equals() method, despite the invocation to this.entries[key] which should trigger the equality comparison. Then the iteration through all the keys yelds the expected result (Name(Size) key exists and is positively equated -- so the problem is NOT in IEquatableName implementation!). So, the problem seems to be that System.Collections.Generic.DictionaryTKey,TValue has a faulty way to access its keys... What do you suggest about it? Is it a reported bug? How can I obtain the correct behavior? Many thanks ___ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list
Re: [Mono-dev] Key matching issue in generic Dictionary [correct message]
Generic 2006 wrote: I'm facing a strange behavior affecting System.Collections.Generic.DictionaryTKey,TValue: when I try to search for a key among the dictionary entries using interface members such as ContainsKey(TKey key) or this[TKey key] I receive wrong responses (the key can't be find, whilst it's really there!). I supposed that it could be a problem on the TKey side (where I implemented System.IEquatableTKey), so I put some Console.WriteLine() inside the code to verify. A System.Collections.Generic.Dictionary instance is incapsulated in MyDictionary (an implementation of generic IDictionary), TKey is assigned to Name type, TValue is irrelevant. IEquatableT is not enough. You need to override Object.GetHashCode() and Object.Equals(). IEquatableT is optional, GetHashCode and Equals are mandatory. --Brian ___ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list
Re: [Mono-dev] Key matching issue in generic Dictionary [correct message]
Brian Crowell wrote: IEquatableT is not enough. You need to override Object.GetHashCode() and Object.Equals(). IEquatableT is optional, GetHashCode and Equals are mandatory. Off the top of my head, this is the proper implementation: class Name : IEquatableName { public Name(string value) { ... } public bool Equals(Name obj) { Console.WriteLine(Name.Equals(): this: + this.value + other: + obj.Value); return this.value.Equals(obj.Value); } public string Value { get{return this.value;} } public override bool Equals( object obj ) { Name other = obj as Name; if( other == null ) return false; return Equals(other); // Calls Equals(Name obj) } public override int GetHashCode() { return value.GetHashCode(); } // Override operator == and operator != as well; // not necessary, but recommended } ___ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list
Re: [Mono-dev] Key matching issue in generic Dictionary [correct message]
On 08/23/2006 04:35 PM, Brian Crowell wrote: Generic 2006 wrote: I'm facing a strange behavior affecting System.Collections.Generic.DictionaryTKey,TValue: when I try to search for a key among the dictionary entries using interface members such as ContainsKey(TKey key) or this[TKey key] I receive wrong responses (the key can't be find, whilst it's really there!). I supposed that it could be a problem on the TKey side (where I implemented System.IEquatableTKey), so I put some Console.WriteLine() inside the code to verify. A System.Collections.Generic.Dictionary instance is incapsulated in MyDictionary (an implementation of generic IDictionary), TKey is assigned to Name type, TValue is irrelevant. IEquatableT is not enough. You need to override Object.GetHashCode() and Object.Equals(). IEquatableT is optional, GetHashCode and Equals are mandatory. --Brian Thank you Brian for your prompt reply: I've just got an analogous hint from the guys at IRC #mono. So I should write something like this (please, let me know): class Name : IEquatableName { public Name(string value) { ... } // Mandatory!!! public override int GetHashCode() { return this.value.GetHashCode(); } // Mandatory!!! public override bool Equals(object obj) { if(obj is Name) return Equals((Name)obj); else return false; } public bool Equals(Name obj) { Console.WriteLine(Name.Equals(): this: + this.value + other: + obj.Value); return this.value.Equals(obj.Value); } public string Value { get{return this.value;} } } ___ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list