Reputation: 50074
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> ?
Upvotes: 0
Views: 1181
Reputation: 1500815
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...
Upvotes: 1
Reputation: 4005
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.
Upvotes: 0