Yanshof
Yanshof

Reputation: 9926

How create class that i can define that is a key in dictionary?

I want to create Dictionary that contain class XX that will be the key and class YY that will be the value.

The Dictionary is define as

    Dictionary<XX, YY> myDictionary; 

The XX class code

class XX 
{
  int t1;
  char t2;

  string Key()
  {
        return string.Format("{0}{1}", t1, t2);
  }
}

I want somehow to define that the Dictionary key is actually XX but using the 'Key' of the class XX as the real key of the dictionary.

is it possible ?

Upvotes: 1

Views: 139

Answers (2)

Lucas Trzesniewski
Lucas Trzesniewski

Reputation: 51330

First method

You have to override two methods of XX:

  • Equals, which will tell the dictionary whether the two instances are equal
  • GetHashCode, which has to return the same number if two instances are equal. Note that it can return the same number if two instances aren't equal too, but you should make it as unique as possible.

You can also implement IEquatable<XX> on the XX class, which will mkae it explicit that XX can compare for equality.

class XX : IEquatable<XX>
{
    int t1;
    char t2;

    public override bool Equals(object other)
    {
        return Equals(other as XX);
    }
    
    public bool Equals(XX other)
    {
        return other != null
            && t1 == other.t1
            && t2 == other.t2;
    }
    
    public override int GetHashCode()
    {
        return t1 ^ (397 * t2.GetHashCode());
    }
}

Second method

Create a class which implements IEqualityComparer<XX> and pass it to the dictionary's constructor. You will have to implement the same two methods, but the logic will be separated from XX, and you will be able to create different dictionaries with different keying schemes.

class XXEqualityComparer : IEqualityComparer<XX>
{
    public static readonly XXEqualityComparer Instance = new XXEqualityComparer();
    
    private XXEqualityComparer()
    {
    }

    public bool Equals(XX x, XX y)
    {
        if (ReferenceEquals(x, y))
            return true;
            
        if (x == null || y == null)
            return false;
            
        return x.t1 == y.t1
            && x.t2 == y.t2;
    }
    
    public int GetHashCode(XX obj)
    {
        return obj == null ? 0 : obj.t1 ^ (397 * obj.t2.GetHashCode());
    }
}

Then:

var myDictionary = new Dictionary<XX, YY>(XXEqualityComparer.Instance);

Third method

Replace the dictionary with a KeyedCollection<XX, string>. You will have to override the GetKeyForItem method to provide a key for an item.

class XXKeyedCollection : KeyedCollection<XX, string>
{
    protected override string GetKeyForItem(XX item)
    {
        return string.Format("{0}{1}", t1, t2);
    }
}

Important note

Please note that in order to have a working dictionary key, the object must not change while it's used as a dictionary key. More precisely, any field/property that would influence the result of Equals or GetHashCode must not change.

Upvotes: 8

shay__
shay__

Reputation: 178

Dictionary class uses the GetHashCode() method on the key object to generate the key in the hash table. Just override it in XX class to return whatever you need, but be careful there (think what might happen if different XX instances with the same key are put in the dictionary).

Upvotes: 2

Related Questions