Use the key "Object as a dictionary"

I want to use the following object as a dictionary. If Category and Target are equal, the key is equal. Any solution?

public class TargetKey { public TargetKey(Categories category_arg, String target_arg) { catetory = category_arg; target = target_arg; } private Categories catetory; public Categories Catetory { get { return catetory; } //set { catetory = value; } } private String target; public String Target { get { return target; } //set { target = value; } } } 

Bad decision

It seems that GetHashCode() is called first, if the hash is equal, then Equals() is called. Therefore, I add the following 2 methods:

  public override bool Equals(object obj) { TargetKey other = obj as TargetKey; return other.Catetory == this.Catetory && other.Target == this.Target; } public override int GetHashCode() { return 0; //this will leads to ONLY 1 bucket, which defeat the idea of Dictionary. } 

Refined solution

  public override bool Equals(object obj) { TargetKey other = obj as TargetKey; return other.Catetory == this.Catetory && other.Target == this.Target; } public override int GetHashCode() { Int32 hash = this.Target.GetHashCode() + this.Catetory.GetHashCode(); // This will introduce some more buckets. Though may not be as many as possible. return hash; } 
+4
source share
4 answers

Override and implement Equals() and GetHashCode() based on your category and purpose, and this will allow you to use them for comparison as a dictionary key.

Here is a recommended implementation, but what needs to be done will depend on whether they can be null or not. I suggested that they might be in the implementation below, since there is no null check in the constructor:

 public class TargetKey { public TargetKey(Categories category_arg, String target_arg) { Catetory = category_arg; Target = target_arg; } private Categories catetory; public Categories Catetory { get { return catetory; } } private String target; public String Target { get { return target; } } public bool Equals (TargetKey other) { if (ReferenceEquals (null, other)) { return false; } if (ReferenceEquals (this, other)) { return true; } return Equals (other.catetory, catetory) && Equals (other.target, target); } public override bool Equals (object obj) { if (ReferenceEquals (null, obj)) { return false; } if (ReferenceEquals (this, obj)) { return true; } if (obj.GetType () != typeof (TargetKey)) { return false; } return Equals ((TargetKey) obj); } public override int GetHashCode () { unchecked { return ((catetory != null ? catetory.GetHashCode () : 0)*397) ^ (target != null ? target.GetHashCode () : 0); } } } 
+4
source

You can override GetHashCode and Equals .

These two methods are used by the Dictionary to determine if two keys are equal. This is also the way in which it looks at the key value. See the GetHashCode documentation for how the dictionary will do this.

[edit]
A (very) rough way to look at the hash code is to index a large array.

 bool ContainsKey(object key) { int hashCode = key.GetHashCode(); object foundKey = this.keys[hashCode]; return key.Equals(foundKey); } 

Please note that this is an extremely simplified way to implement a dictionary. A real dictionary will not have a huge array. This dictionary will perform a null check. A real dictionary can handle different keys with the same hash code, although some keys will affect performance. and etc.

+1
source

If the key is part of a class, use KeyedCollection. This is a dictionary in which the key is obtained from the object. Under the covers is a dictionary. No need to repeat the key in Key and Value. Why risk a key is not a key as a value. No need to duplicate the same information in memory.

You did not specify the category or categories that were used on this line.

KeyedCollection Class

Composite key indexer

 using System.Collections.ObjectModel; namespace KeyCollStringString { class Program { static void Main(string[] args) { StringStringO ss1 = new StringStringO("Sall","John"); StringStringO ss2 = new StringStringO("Sall", "John"); if (ss1 == ss2) Console.WriteLine("same"); if (ss1.Equals(ss2)) Console.WriteLine("equals"); // that are equal but not the same I don't override = so I have both features StringStringCollection stringStringCollection = new StringStringCollection(); // dont't have to repeat the key like Dictionary stringStringCollection.Add(new StringStringO("Ringo", "Paul")); stringStringCollection.Add(new StringStringO("Mary", "Paul")); stringStringCollection.Add(ss1); //this would thow a duplicate key error //stringStringCollection.Add(ss2); //this would thow a duplicate key error //stringStringCollection.Add(new StringStringO("Ringo", "Paul")); Console.WriteLine("count"); Console.WriteLine(stringStringCollection.Count.ToString()); // reference by ordinal postion (note the is not the long key) Console.WriteLine("oridinal"); Console.WriteLine(stringStringCollection[0].GetHashCode().ToString()); // reference by index Console.WriteLine("index"); Console.WriteLine(stringStringCollection["Mary", "Paul"].GetHashCode().ToString()); Console.WriteLine("foreach"); foreach (StringStringO ssO in stringStringCollection) { Console.WriteLine(string.Format("HashCode {0} String1 {1} String2 {2} ", ssO.GetHashCode(), ssO.String1, ssO.String2)); } Console.WriteLine("sorted by date"); foreach (StringStringO ssO in stringStringCollection.OrderBy(x => x.String1).ThenBy(x => x.String2)) { Console.WriteLine(string.Format("HashCode {0} String1 {1} String2 {2} ", ssO.GetHashCode(), ssO.String1, ssO.String2)); } Console.ReadLine(); } public class StringStringCollection : KeyedCollection<StringStringS, StringStringO> { // This parameterless constructor calls the base class constructor // that specifies a dictionary threshold of 0, so that the internal // dictionary is created as soon as an item is added to the // collection. // public StringStringCollection() : base(null, 0) { } // This is the only method that absolutely must be overridden, // because without it the KeyedCollection cannot extract the // keys from the items. // protected override StringStringS GetKeyForItem(StringStringO item) { // In this example, the key is the part number. return item.StringStringS; } // indexer public StringStringO this[string String1, string String2] { get { return this[new StringStringS(String1, String2)]; } } } public struct StringStringS { // required as KeyCollection Key must be a single item // but you don't reaaly need to interact with Int32Int32s public readonly String String1, String2; public StringStringS(string string1, string string2) { this.String1 = string1.Trim(); this.String2 = string2.Trim(); } } public class StringStringO : Object { // implement you properties public StringStringS StringStringS { get; private set; } public String String1 { get { return StringStringS.String1; } } public String String2 { get { return StringStringS.String2; } } public override bool Equals(Object obj) { //Check for null and compare run-time types. if (obj == null || !(obj is StringStringO)) return false; StringStringO item = (StringStringO)obj; return (this.String1 == item.String1 && this.String2 == item.String2); } public override int GetHashCode() { int hash = 17; // Suitable nullity checks etc, of course :) hash = hash * 23 + String1.GetHashCode(); hash = hash * 23 + String1.GetHashCode(); return hash; } public StringStringO(string string1, string string2) { StringStringS stringStringS = new StringStringS(string1, string2); this.StringStringS = stringStringS; } } } } 
0
source

Just use a common set of dictionaries (C # code)

 Dictionary<TargetKey> objMyCollection = new Dictionary<TargetKey>.(); 

Use the ContainsKey () method for objMyCollection as:

 if(objMyCollection.ContainsKey(new TargetKey()) { MessageBox.Show("Obj find"); } else { MessageBox.Show("key not found add new one"); } 
-1
source

Source: https://habr.com/ru/post/1345208/


All Articles