HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Custom key class for .NET 3.5 framework

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
customnetforclasskeyframework

Problem

I use .NET 3.5 framework, so no tuples. I have many use cases where I have to create a custom key for a dictionary. How can I make this better?

public class CompositeKey
{
    public T Content { get; set; }
    public Func[] Lambdas { get; set; }

    public CompositeKey(T obj, params Func[] propLambdas)
    {
        Content = obj;
        Lambdas = propLambdas;
    }

    public override int GetHashCode()
    {
        int hash = 0;
        foreach (var l in Lambdas)
        {
            hash ^= l(Content).GetHashCode();
        }
        return hash;
    }

    public override bool Equals(object obj)
    {
        bool isEqual = true;
        if (obj is T)
        {
            T o = (T)obj;
            foreach (var l in Lambdas)
            {
                isEqual &= (l(Content) == l(o));
            }
            return isEqual;
        }
        return false;
    }
}

public class TestCode
{
    public void somemethod()
    {
        Dictionary, string> dict = new Dictionary, string>();
        var t1 = new TestPOCO() { ID=1, Name="A" };
        var t2 = new TestPOCO() { ID = 2, Name = "B" };
        dict.Add(new CompositeKey(t1, x => x.ID, x => x.Name) , t1.Name);
        dict.Add(new CompositeKey(t2, x => x.ID, x => x.Name), t2.Name);
    }
}

public class TestPOCO
{
    public int ID;
    public string Name;
}


Especially this part:

dict.Add(new CompositeKey(t1, x => x.ID, x => x.Name) , t1.Name);
        dict.Add(new CompositeKey(t2, x => x.ID, x => x.Name), t2.Name);


The challenge is to have lambda defined only once, but have different key objects based on the POCO.

Solution

-
Mutable keys are a very bad idea, try this:

public void Foo()
{
    var mutable = new Mutable { Value = 1 };
    var dictionary = new Dictionary { { mutable, "one" } };
    mutable.Value = 2;
    var explodesHere = dictionary[mutable];
}

public class Mutable
{
    public int Value;

    public override int GetHashCode()
    {
        return Value;
    }
}


-
GetHashCode must not change while the instance is used in a collection that relies on the value. There are two ways to solve this:

  • Calculate the hash from values that cannot change. Prefer this wherever possible.



  • Make sure that the values affecting the hash are not changed while the instance is used in a collection. This is a pit of failure.



-
You can create a dictionary passing in an IEqualityComparer

-
About your example:

ID reads like a property that uniquely identifies an entity and does not change.
If this is the case it is a nice candidate to use as a key. I'm guessing a bit here but I'm getting a feeling you really want:

var idNameMap = new Dictionary();
idNameMap.Add(t1.ID, t1.Name);

Code Snippets

public void Foo()
{
    var mutable = new Mutable { Value = 1 };
    var dictionary = new Dictionary<Mutable, string> { { mutable, "one" } };
    mutable.Value = 2;
    var explodesHere = dictionary[mutable];
}

public class Mutable
{
    public int Value;

    public override int GetHashCode()
    {
        return Value;
    }
}
var idNameMap = new Dictionary<int, string>();
idNameMap.Add(t1.ID, t1.Name);

Context

StackExchange Code Review Q#122514, answer score: 3

Revisions (0)

No revisions yet.