Reputation: 387
I am building the following class to manage a dictionary.
public class EnumDictionary<TKey, TValue>
{
private Dictionary<TKey, TValue> _Dict;
public EnumDictionary(Dictionary<TKey, TValue> Dict)
{
this._Dict = Dict;
}
public TKey GetValue(TValue value)
{
foreach (KeyValuePair<TKey, TValue> kvp in _Dict)
{
if (kvp.Value == value)
return kvp.Key;
}
throw new Exception("Undefined data type: " + value);
}
}
But I am getting an error "Operator '==' cannot be applied to operands of type 'TValue' and 'TValue'".
BTW, I am making this custom collection is because my dictionary has unique value, but I can't get key by value from a dictionary.
Any help is appreciated. Thank you.
Upvotes: 2
Views: 630
Reputation: 113232
If you want this to be general purpose, then you will want the definition of equality to be configurable, just as it is in the dictionary for keys.
Have a property of type IEqualityComparer<TValue>
, which is set in the constructor.
Then have a version of the constructor that makes the default EqualityComparer<TValue>.Default
. This will work by calling Equals
on the type in question.
public class EnumDictionary<TKey, TValue>
{
private Dictionary<TKey, TValue> _Dict;
private readonly IEqualityComparer<TValue> _cmp;
public EnumDictionary(Dictionary<TKey, TValue> Dict, IEqualityComparer<TValue> cmp)
{
this._Dict = Dict;
_cmp = cmp;
}
public EnumDictionary(Dictionary<TKey, TValue> Dict)
:this(Dict, IEqualityComparer<TValue>.Default){}
public TKey GetValue(TValue value)
{
foreach (KeyValuePair<TKey, TValue> kvp in _Dict)
{
if (cmp.Equals(kvp.Value, value))
return kvp.Key;
}
throw new Exception("Undefined data type: " + value);
}
}
Upvotes: 0
Reputation: 128317
Fredrik is right; you need to use Equals
as you can't presume to be able to use ==
for all types, since the operator isn't defined for every type.
Depending on your scenario, it might also make sense to add
where TValue : IEquatable<TValue>
as a generic type constraint on your class. The reason for this is that object.Equals
accepts another object
as a parameter, which means that if TValue
is a value type it will be boxed. If it can be known to implement IEquatable<TValue>
, on the other hand, then Equals
can be resolved to IEquatable<TValue>.Equals
*, which takes a TValue
as a parameter and therefore won't require value types to be boxed.
I might also recommend that you rethink the internal structure of this class. As it currently stands, there's no reason you need this class at all, as you could easily add an extension method to IDictionary<TKey, TValue>
to find a key by value via enumeration over the values. What I would do instead is store two dictionaries: a Dictionary<TKey, TValue>
and a Dictionary<TValue, TKey>
, so that two-way lookup is possible in O(1).
*By the way, in case you're curious, the reason you can't use IEquatable<T>
(or any interface for that matter) to ensure that a type has implemented the ==
operator is that operators are static, and interfaces cannot provide static methods (and thus can't provide operators).
Upvotes: 3
Reputation: 101130
Don't create a new class. Create a extension method:
public static class DictionaryHelper
{
public static TKey GetKeyFromValue<TKey, TValue>(this IDictionary<TKey, TValue> instance, TValue value)
{
foreach (var kvp in instance)
{
if (kvp.Value.Equals(value))
return kvp.Key;
}
return default(TKey);
}
}
public class Example
{
public static void Main(string[] argv)
{
Dictionary<string, string> test = new Dictionary<string, string> { { "Mykey", "MyValue" }, { "Key1", "Value2" } };
string key = test.GetKeyFromValue("MyValue");
}
}
Upvotes: 0
Reputation: 1346
Use the "where" condition on your generic types
class Dictionary<TKey,TVal>
where TKey: IComparable, IEnumerable
where TVal: MyI
{
public void Add(TKey key, TVal val)
{
}
}
from http://msdn.microsoft.com/en-us/library/6b0scde8%28VS.80%29.aspx
Upvotes: 0
Reputation: 158289
Did you try using the Equals
method?
if (kvp.Value.Equals(value))
I think this restriction is due to the fact that the ==
operator can't be used with all types. Take the following for instance:
struct Test
{
public int Value;
}
Given the above struct, the following code will not compile:
Test a, b;
a = b = new Test();
bool areEqual = a == b; // Operator '==' cannot be applied to
// operands of type 'Test' and 'Test'
However, all types have the Equals
method, so calling that will work:
Test a, b;
a = b = new Test();
bool areEqual = a.Equals(b);
Upvotes: 5
Reputation: 6543
When you use generic comparsions I think you should implement a (x)CompareTo(Y) or a comparable class. Please correct me if im wrong.
Upvotes: 0