Vinicius Silveira
Vinicius Silveira

Reputation: 27

Check if Dictionary has a Value in any of its Keys

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

Answers (5)

dcastro
dcastro

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

Tomasz Jaskuλa
Tomasz Jaskuλa

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

Jon
Jon

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

Mateusz
Mateusz

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

decPL
decPL

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

Related Questions