-1

This is my code:

public class MyKeyType
{
    public int x;
    public string operationStr;
}

private static Dictionary<MyKeyType, List<int>> m_Dict = new Dictionary<MyKeyType, List<int>>
{
    { new MyKeyType { x = MyValsType.File, operationStr = "LINK" },   new List<int> { 1,2,3,4,5  }  }, 
    { new MyKeyType { x = MyValsType.File, operationStr = "COPY" },   new List<int> { 10,20,30,40,50  }  }, 
    .....
}

List<int> GetValList( int i, string op)
{ 
    // The following line causes error:
    return ( m_Dict [ new MyKeyType { x = i, operationStr = op } ] );
}

But I get the error "The given key was not present in the dictionary" when I call:

GetValList( MyValsType.File, "LINK");

Can you tell why? Many thanks in advance.

dghadagh
  • 103
  • 1
  • 15
  • 1
    You pass new object to dictionary, so it doesn't exist there. – Maxim Goncharuk Dec 05 '15 at 09:24
  • Thanks Maxim. But is there any other way without using new keyword? I suppose to lookup corresponding values for (MyValsType.File, "LINK"), and I don't intend to use "new", but I don't know how to setup a proper argument for this purpose otherwise. – dghadagh Dec 05 '15 at 09:27
  • 1
    Why? Because the given key doesn't exist in the dictionary. I guess that you want to find the key whose properties (`x` and `operationStr`) match the ones of a previous entry, but this doesn't mean that the entry is the same. For example: `MyKeyType test = new MyKeyType { x = 1, operationStr = "1" }; m_Dict.Add(test, new List() { 1, 2, 3 });` if you now do `MyKeyType test0 = new MyKeyType {x = 1, operationStr = "1" }; List test2 = m_Dict[test0];` you would get an error. BTW, next time you should try to make a small effort ask clearly, for example with a simple example like this one. – varocarbas Dec 05 '15 at 09:28
  • You may simplify your key to simple value like `Dictionary>` Or you can keep your keys in other list. – Maxim Goncharuk Dec 05 '15 at 09:28
  • 1
    @MaximGoncharuk Recommending to plainly redefine the given variable is rarely a good advice. You don't know why the OP wants this data structure. – varocarbas Dec 05 '15 at 09:29
  • 1
    There are various options to accomplish what you. You might either look for entries matching the given properties (via conventional loop or LINQ); or you might redefine your class such that certain comparisons are inmediately supported (for example: http://stackoverflow.com/questions/4188013/c-sharp-interfaces-how-to-implement-icomparable). – varocarbas Dec 05 '15 at 09:32
  • 2
    You did not override Equals and GetHashCode nor did you provide the dictionary with an IEqualityComparer so a new object of type MyKeyType is never going to match one that is stored in the dictionary. A class that exposes fields like that is not a great candidate for a dictionary key btw, it is much too easy to change a field and make a dictionary entry get irretrievably lost. – Hans Passant Dec 05 '15 at 09:34
  • Yes Varocarbas. I cannot use Maxim's recommendation for simplifying. Indeed, my data structures are very complicated than to be posted here, and I have simplified it for this post. – dghadagh Dec 05 '15 at 09:36
  • Thanks varocarbas. Do you mean lookup facility for primitive types as keys are provided as pre-built for dictionaries, but for user-defined types needs to be supplied by the user? – dghadagh Dec 05 '15 at 09:45
  • 1
    Yes. When creating a class you are basically defining a new type and that's why you have to add all the "features you want" (the in-built functionalities in dictionaries and everywhere else work based on certain underlying information which your class has to provide). For example, Hans Passant is telling you what to do to allow the given instance of your class to be recognised right away by the dictionary as equivalent to another one with the same properties. – varocarbas Dec 05 '15 at 09:54
  • Thanks varocarbas. Thanks so much Hans. – dghadagh Dec 05 '15 at 10:38

2 Answers2

4

When you use a class as a key for a dictionary, the class has to correctly implement GetHashCode() and Equals: Dictionary calls these two methods to understand that that "that key" is the same that "that other key": if 2 instances x and y return same value for GetHashCode() and x.Equals(y) == true; the 2 keys match.

Not providing the two overrides in your MyKeyType class will result in object.GetHashCode() and object.Equals being called at runtime: these will return a match only if x and y are a reference to the same instance (i.e. object.ReferenceEquals(x, y) == true)

Many .Net framework types (e.g. string, numeric types, dateTime, etc) implements correctly the two methods. For your defined classes, you have to implement them in your code

Gian Paolo
  • 4,161
  • 4
  • 16
  • 34
1

If you are able to use LINQ, you can change your GetValList() to:

 static List<int> GetValList(int i, string op)
    {
       return m_Dict.Where(x => x.Key.x == i && x.Key.operationStr.Equals(op)).Select(x => x.Value).FirstOrDefault(); 
    }
HSS
  • 38
  • 5