Reputation: 27
So, I have a Dictionary and I need to check if in any of its Keys
is there a certain Value
present. As value, I use this class:
class Symbols
{
public bool OPC { get; set; }
public string Type { get; set; }
}
And, I am assigning the dictionary with the following key and values:
public static Dictionary<string, Symbols> SymbolDictionary = new Dictionary<string, Symbols>(StringComparer.CurrentCultureIgnoreCase);
Symbols symbol = new Symbols();
symbol.OPC = false;
symbol.Type = "Type";
SymbolDictionary.Add(Key,symbol);
If I check for SymbolDictionary[Key].symbol.OPC
(or .symbol.Type
) I get exactly the right values. But when I try to do this in a if, it never returns true
:
if (SymbolDictionary.ContainsValue(symbol)) Console.WriteLine("Something");
As it never find a match of the values, even if I add the value and check it with the if
statement right away. Any hints about how could I do that?
Upvotes: 2
Views: 1651
Reputation: 68660
The code you provided works fine.
What you're actually doing though, is probably slightly different from what you've posted.
You're probably creating a new Symbols
object, correct? This would fail:
Symbols symbol = new Symbols();
symbol.OPC = false;
symbol.Type = "Type";
SymbolDictionary.Add("key", symbol);
//create new instance
symbol = new Symbols();
symbol.OPC = false;
symbol.Type = "Type";
Debug.WriteLine(SymbolDictionary.ContainsValue(symbol));
You should implement the IEqualityComparer<Symbols>
interface and its Equals
and GetHashCode
methods.
Now, the problem is, a dictionary stores your items in buckets depending on its hash code (provided by GetHashCode
).
You'd have to make sure that two Symbols
return the same hashcode.
Your calculation of a hash should NOT depend on OPC
or Type
properties though: the hashcode of an object must remain the same while it's being stored in a hash map (e.g. dictionary).
And because those two properties can change, so can a hashcode that depends on them. And that would break the usefulness of a dictionary.
Guidelines and rules for implementing GetHashCode: http://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/
Upvotes: 2
Reputation: 16013
In addition to this topic one may ask if it is enough to just override Equals
and GetHashCode
methods on the Symbol class ?
When you override Equals
and GetHashCode
you are changing the way the object will determine if it is equals to another. And a note, if you compare objects using ==
operator it will not have the same behavior as Equals unless you override the operator as well.
Doing that you changed the behavior for a single class, what if you need the same logic for other classes? If you need a "generic comparison". That is why you have IEqualityComparer
.
Upvotes: 0
Reputation: 437376
TL;DR: your Symbols
class must implement IEquatable<Symbols>
in order for the comparison to work "as intended", or you must install a custom equality comparer when constructing the dictionary.
The ContainsValue
method uses EqualityComparer<T>.Default
as the method for comparing the specified value with the values in the dictionary for purposes of determining equality. If the class T
does not implement IEquatable<T>
then the default equality comparer uses reference equality; this means that this comparison won't work:
Symbols symbol1 = new Symbols();
Symbols symbol2 = new Symbols();
SymbolDictionary.Add("key", symbol1);
if (SymbolDictionary.ContainsValue(symbol2)) ... // false!
So first you must decide what "equal" means in the context of a symbol, and then implement the equality comparison accordingly. Make sure to read and heed the remarks in the IEquatable<T>
documentation when implementing!
Upvotes: 3
Reputation: 2317
As you can read in: http://msdn.microsoft.com/en-us/library/a63811ah(v=vs.110).aspx
This metod uses default equality comparer, so you have to implement IEquatable:
class Symbols : IEquatable<Symbols>
{
public bool OPC { get; set; }
public string Type { get; set; }
public bool Equals(Symbols other)
{
//here your comparision code
}
}
Upvotes: 1
Reputation: 5402
That's because you haven't provided any comparison methods for your class.
The Default property checks whether type T implements the System.IEquatable interface and, if so, returns an EqualityComparer that uses that implementation. Otherwise, it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T.
Some further reading:
Upvotes: 4