tags:

views:

308

answers:

2

What is the best way to make a generic equivalence function for two Dictionaries, whose keys and values are value types?

Right now I have a Dictionary<string, bool>, and have created an extension method that (I think) works to test for equivalence between two Dictionary<string, bool>.

I wanted to make it more generic. And my first thought was to make it like this:

public static bool EquivalentTo<K, V>(this IDictionary<K, V> lhs, 
                                           IDictionary<K, V> rhs) 
        where K: struct 
        where V: struct
    { }

However, this doesn't work because strings are immutable reference types, and NOT a value type.

So how would one go about generic-izing my original Equivalence test for Dictionary<string, bool> ?

A: 

I can't think of a way to do exactly what you're looking for in a single construct. You could have overloads that explicitly use string instead of a template parameter for the type, so you'd end up with 3 overloads:

public static bool EquivalentTo<string, V>(this IDictionary<string, V> lhs, 
                                                IDictionary<string, V> rhs) 
    where V: struct
{ }
public static bool EquivalentTo<K, string>(this IDictionary<K, string> lhs, 
                                                IDictionary<K, string> rhs) 
    where K: struct
{ }
public static bool EquivalentTo<K, V>(this IDictionary<K, V> lhs, 
                                           IDictionary<K, V> rhs) 
    where K: struct 
    where V: struct
{ }

I'm pretty sure that's not what you're looking for, but I don't have any better ideas off the top of my head.

scwagner
Well I could always make it type Dictionary<string, V>
Alex Baranosky
Right, if your key is always a string.
scwagner
+1  A: 

Why do you want to restrict K and V to being value types in the first place? I suggest you just remove the constraints. There are "interesting" things about dictionaries though - are two dictionaries which happen to have the same entries, but use different equality comparers equivalent? IDictionary<,> doesn't have an equality comparer property, unfortunately, so you may need to provide on to your equivalence method. You'll need to consider what it even means to be equivalent here.

For example, two dictionaries both with case-insensitive equality comparers might have { "FOO", true } and { "foo", true } - to some extent they're equivalent, but to some extent they aren't. It depends on what you want to use the equivalence relation for.

EDIT: Here's an example which should be fine in most cases, but could give odd results if the two dictionaries treat keys differently:

public static bool EquivalentTo<TKey, TValue>(
     this IDictionary<TKey, TValue> first,
     IDictionary<TKey, TValue> second)
{
     return first.EquivalentTo(second, EqualityComparer<TValue>.Default);
}

public static bool EquivalentTo<TKey, TValue>(
     this IDictionary<TKey, TValue> first,
     IDictionary<TKey, TValue> second,
     IEqualityComparer<TValue> valueComparer)
{
    if (first == second)
    {
        return true;
    }
    if (first == null || second == null)
    {
        return false;
    }
    if (first.Count != second.Count)
    {
        return false;
    }
    foreach (var firstKeyValue in first)
    {
        TValue secondValue;
        if (!second.TryGetValue(firstKeyValue.Key, out secondValue) ||
            !valueComparer.Equals(firstKeyValue.Value, secondValue))
        {
            return false;
        }
    }
    return true;
}

Untested, but let me know if it does what you want...

Jon Skeet
Really at this point all I need is the non-generic version, but I like experimenting and learning as I go. Your post gives me food for thought, so I have succeeded :)
Alex Baranosky
My reasoning for having K and V be value types was that I could make a straightforward test for equivalence, if they are reference types then the test for equivalence becomes much less straightforward.
Alex Baranosky
Use an Iequalitycomparer to do the comparisons - more info when I'm not walking and typing on a phone.
Jon Skeet
very nice. I was doing something similar but catching a KeyNotFoundException. The TryGetValue is much better. Thanks.
Alex Baranosky
In C# is the Or lazy? So if the first half fails, it doesn't execute the right?
Alex Baranosky
Short Circuit Evaluation yes. VB is very unusual in language terms for in not doing this...
ShuggyCoUk
Short circuit, yes, that is the term i was looking for. Thanks Shuggy
Alex Baranosky