KeyedCollection default key comparison

JaedenRuiner

Well-known member
Joined
Aug 13, 2007
Messages
340
Programming Experience
10+
When using the generic class
VB.NET:
Inherits System.Collections.ObjectModel.KeyedCollection(Of TKey, TItem)

what is the standard comparison used for TKey comparison when the TKey supplied type is that of a a class object.

I was hoping/expecting that it would use the Object.Equals() extension or some derivation which is why I overrode it in my TKey class, but now i'm thinking it might use references which would naturally fail.

However, if it does work via comparing references, how would I override the built in Comparer , since the property is readonly.

thanks
 
Huh???

Okay,

So i tried creating my own IEqualityComparer implementation (decending from the generic EqualityComparer(of T) class provided, and hooked that into my KeyedCollection. But the darn thing doesn't event use the "MustOverride" method of Equal(x as Tkey, Y as TKey) it uses the GetHashCode(obj as T) method. What good is that. Do i have to devise some hash code calculation based off of the data in my Key object to get this to work?

basically I want this:

VB.NET:
public class MyKey
  private _name as string
  private _value as string

'<funky formatting and transitional data>'
'unimportant to the question'

   Public Overrides Function Equals(ByVal obj As Object) As Boolean
      Return (TypeOf obj Is NameValuePair) AndAlso _name.Equals(DirectCast(obj, NameValuePair)._name, _case)
   End Function

as you can see as long as the to name fields are equal Key1 and Key2 are the same even if they are different references, but that isn't computed by the Hashcode or whatnot the keyedcollection is using.

suggestions?
thanks
 
EDIT:
It seems as Equals method of the Key class is used to determine if the objects are equal, in which case the GetHashCode method is used as key in dictionary(?) (see Hashtable Class help for more info about this behaviour). If your key class for example has an Id property you can do this:
VB.NET:
Public Overrides Function GetHashCode() As Integer
    Return Me.id.GetHashCode()
End Function

Public Overrides Function Equals(ByVal obj As Object) As Boolean
    Return (Me.id = CType(obj, Key).id)
End Function
This seems like a flaw in the Hashtable since you can use the same key reference and change its 'id' to a new value and it will pass, if you lookup the old id value and check the item key you see it doesn't have that key id any longer. This doesn't correlate well in my opinion with KeyedCollection where the item is supposed to hold the key.
 
Last edited:
EDIT: Ah, found it. It was a versionary compilation issue at this point. By overriding the TKey.GetHashCode() and the TKey.Equals when the HashCode is requested from the IEqualityComparer, if they are equal it then uses the IEqualityComparer.Equals() method to see if the Keys are Equal and then it finds the key. Rather complicated for something that should be relatively simple.

Hrm...

well this is the amusing thing:
VB.NET:
Me.Item(Items(0).Key)
Produces Exception:
The generic type 'FlufLib.FlufKeyedList`2' was used with the wrong number of generic arguments in assembly 'FlufLib, Version=1.0.3181.30039, Culture=neutral, PublicKeyToken=null'.

AND

VB.NET:
Me.Dictionary.Item(items(0).Key)
Produces Exception:
The given key was not present in the dictionary.

And as you can see, that is using the actual item key from an item in the list, and their actual keys, so i have to ask...what's the point? It appears that the Dictionary Class and the KeyedCollection class are completely worthless because they only work on simple types, ints, strings, etc.
Is there no way to utilize a complex object key as the key for a keyedcollection?

thanks
 
Last edited:
The given key was not present... well weren't you overriding the key to use some part of that key only? As in my above example it is not actually the "key" class instance that is used as key, but the Id property of it.
 
There is a glitch with the above solution, I had the Id as Integer and it got mixed up with the collection index in my tests, so while the custom comparison were functional the key indexer never worked. Here is another work around, a hack actually, to set a new internal comparer:
VB.NET:
Dim kc As New KeyedColl
Dim fi As Reflection.FieldInfo = kc.GetType.BaseType.GetField("comparer", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
fi.SetValue(kc, New customcompare)
Keyedcoll inherits KeyedCollection, customcompare implements EqualityComparer(Of TKey).

As mentioned, this whole setup could get confusing for user, since the key is not actually used as key, and changing that part of the item key will suddenly bring up and different item.
 
I solved that the other way. The default constructors for keyedcollection(T) base have a parameter for the Comparer class. So i overrode them and made sure to provide my own Comparer decendent class, making the key comparison an internal event for future decendents of my keyedcollection class. Thus I can always trap KeyCompare() even in any situation and determine my own equals.

I also found that if I override the hash computation in my key class as well as the equals computation, I can call both of those in my EqualityComparer GetHashCode() and Equals() methods, and it all works.
It took a rebuild to get some of the changes to take effect which is why I initially thought it wouldn't work.

thanks
 
The default constructors for keyedcollection(T) base have a parameter for the Comparer class.
Oh my, can't believe I missed that, good going :)
 
Back
Top