Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to derive a unique dictionary key for an object?

PROBLEM

I need a method for generating keys for a dictionary of objects. However, I have a few requirements that are making this a bit difficult. Here is the scenario:

  1. The Dictionary is a list of reference type objects.
  2. The Dictionary is private, within a static class.
  3. External code needs to obtain a key to specific objects within the dictionary, but MUST NOT have access to the objects within the dictionary, or the dictionary itself.
  4. Given a specific object within the dictionary, the key must be consistently re-calculable/derivable. If properties on the object change, the key MUST NOT CHANGE.
  5. Conversely, if a new object is created that can evaluate to being equal to another object within the dictionary, the key must be different since they are two, separate objects.
  6. This implementation must be thread safe.

NON-SOLUTIONS

Solution #1
All .Net objects contain a method called .GetHashCode(), which returns an integer value. You can use this as a key.

Problem
Not possible. MSDN States:

Two objects that are equal return hash codes that are equal.

This breaks req #5 and I assume (but not tested) req. #4. I would love to have an option like this, if it could meet these rules.

Solution #2
Convert the pointer to the object to an int and use that as a key.

Problem
This breaks the essence of req. #3. Passing pointers, and using them as keys doesn't feel safe.

Solution #3
Convert the pointer to the object to an integer hash the value and use the hash as a key.

Problem
Although this doesn't break any rules, I'd prefer to avoid accessing pointers since this would involve using unsafe code. I'm not opposed to using unsafe code if I have to, but I'd prefer to avoid it if at all possible.

CONCLUSION

Maybe my requirements are a bit picky. There has to be some reasonable way of deriving a key from a unique object. Has anyone ever experienced such a scenario and solved this dilemma?

like image 217
RLH Avatar asked Nov 21 '25 11:11

RLH


2 Answers

1 The Dictionary is a list of ByRef objects.

Objects are always 'by reference' in .NET. This may be the beginning of the misunderstanding. Reference equality is what you need/want.

3 External code needs to obtain a key to specific objects within the dictionary, but MUST NOT have access to the objects within the dictionary, or the dictionary itself.

This is the real problem. Without it, a reference to the object itself would have worked. But the framework still provides all of your functionality, right off-the-shelf:

private Dictionary<object, MyClass> _myStore;

// add an item and return a key    
public object Add(MyClass item)
{
    object key = new object();
    _myStore.Add(key, item);
    return key;
}

And to satisfy req #4:

private Dictionary<object, MyClass> _itemForKey;    // was _myStore
private Dictionary<MyClass, object> _keyForItem;


// add an item and return a key    
public object Add(MyClass item)
{
    object key = new object();
    _itemForKey.Add(key, item);
    _keyForItem.Add(item, key);
    return key;
}

protected object DeriveKeyFromItem(MyClass item)
{
   return _keyForItem[item];
}

Note: these samples are not thread-safe (req 6), but that's a standard feature to resolve.

like image 159
Henk Holterman Avatar answered Nov 23 '25 23:11

Henk Holterman


I think that your requirement boils down to that you want to compare and hash by reference equality. Using this as the IEqualityComparer<T> in your dictionary will do that, using RuntimeHelpers.GetHashCode and object.ReferenceEquals.

public class ReferenceEqualityComparer<T> : IEqualityComparer<T>
{
    public bool Equals(T x, T y)
    {
        return object.ReferenceEquals(x, y);
    }
    public int GetHashCode(T obj)
    {
        return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
    }
}

Note that since pointers and references aren't the same, your reference shouldn't be usable as a pointer, reducing the risk of unsafe code using this inappropriately.

like image 41
Tim S. Avatar answered Nov 24 '25 00:11

Tim S.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!