字典C中的GetHashCode和Equals实现#

我来到这个网站,在Dictionary中搜索对象比较,我开始知道重写GetHashCode和Equals是在C#中进行对象比较的必要条件。 这是我尝试使用FOREACH迭代方法解决的一段代码。 但是由于性能问题,我的Boss说不使用任何迭代(可能使用containskey或containsvalue方法)也是如此。 任何帮助都非常欢迎..

public class employee { public string empname { get; set; } public string location { get; set; } public double kinid { get; set; } public double managerKin { get; set; } public override bool Equals(object obj) { return base.Equals(obj); } public override int GetHashCode() { return base.GetHashCode(); } } public class manager { public string managername { get; set; } public double kinid { get; set; } public override int GetHashCode() { return 17 * managername.GetHashCode() + kinid.GetHashCode(); } } public class program { public static void Main() { employee emp = new employee(); employee emp2 = new employee(); manager mng = new manager(); manager mng2 = new manager(); emp.empname = "Deepak"; emp.location = "Pune"; emp.kinid = 36885; emp.managerKin = 007; emp2.empname = "Astha"; emp2.location = "Pune"; emp2.kinid = 30000; emp2.managerKin = 007; mng.kinid = 007; mng.managername = "Gaurav"; mng2.kinid = 001; mng2.managername = "Surya"; Dictionary relations = new Dictionary(); relations.Add(emp, mng); relations.Add(emp2, mng2); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("The Manager details are :"); foreach (var element in relations) Console.WriteLine(" \n KINID : {0} \n Manager'sName : {1}",element.Value.kinid, element.Value.managername); Console.WriteLine("Enter the details of the manager.."); Console.ForegroundColor = ConsoleColor.Gray; Console.Write("\nManager's Kin : "); double mkin = Convert.ToDouble(Console.ReadLine()); Console.Write("Manager's Name : "); string mname = Console.ReadLine(); manager mng1 = new manager(); mng1.kinid = mkin; mng1.managername = mname; int hashvalue = 17 * mname.GetHashCode() + mkin.GetHashCode(); #region BY USING FOREACH LOOP int i = 0; foreach (var element in relations) { if (element.Value.GetHashCode() == hashvalue) { i += 1; if (i == 1) { Console.WriteLine("The Following employees report to the Manager : {0}", mname); } Console.WriteLine(element.Key.empname + " " + element.Key.kinid + " " + element.Key.location + " " + element.Key.managerKin); } } if (i == 0) { Console.WriteLine("sorry the manager's details you entered \"{0}\" \"{1}\" does not exist in our database..", mng1.managername, mng1.kinid); } #endregion Console.ReadLine(); } } 

为了使用ContainsKey或ContainsValue关键字在字典中搜索对象,编译器使用两个隐式函数,即GetHashCode()和Equals()。 所以当我们有一个比较对象时,我们需要覆盖这两种方法!!

这是代码

 #region USING DICTIONARY TO STORE CLASS OBJECTS (check employee existence and print manager's name) public class employee { public string empname { get; set; } public string location { get; set; } public double kinid { get; set; } public double managerKin { get; set; } //public override bool Equals(object obj) // ANY OF THE TWO EQUALS METHOD WORKS. //{ // employee otheremployee; // otheremployee = (employee)obj; // return (otheremployee.kinid == this.kinid && otheremployee.location == this.location && otheremployee.empname == this.empname && otheremployee.managerKin == this.managerKin); //} public override bool Equals(object obj) //When Running this entire code, put a break-point on both the Equals() and GetHashCode() methods, and see the execution flow. { employee otheremployee; otheremployee = (employee)obj; return (obj.GetHashCode() == otheremployee.GetHashCode()); } public override int GetHashCode() //When Running this entire code, put a break-point on both the Equals() and GetHashCode() methods, and see the execution flow. { //int temp = base.GetHashCode(); // DONT USE THIS //return base.GetHashCode(); int temp = empname.GetHashCode() + location.GetHashCode() + kinid.GetHashCode() + managerKin.GetHashCode(); return temp; } } public class manager { public string managername { get; set; } public double kinid { get; set; } public override int GetHashCode() { return base.GetHashCode(); } public override bool Equals(object obj) { return base.Equals(obj); } } public class program { public static void Main() { employee emp = new employee(); employee emp2 = new employee(); manager mng = new manager(); manager mng2 = new manager(); emp.empname = "Deepak"; emp.location = "Pune"; emp.kinid = 36885; emp.managerKin = 007; emp2.empname = "Astha"; emp2.location = "Pune"; emp2.kinid = 30000; emp2.managerKin = 001; mng.kinid = 007; mng.managername = "Gaurav"; mng2.kinid = 001; mng2.managername = "Surya"; Dictionary relations = new Dictionary(); relations.Add(emp, mng); // put a BreakPoint here and see the execution flow relations.Add(emp2, mng2);// put a BreakPoint here and see the execution flow Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("The Employee details are :"); foreach (var element in relations) Console.WriteLine(" \n Employee Name : {0} \n Location : {1} \n Employee KinId : {2} \n Manager's KinId : {3} ", element.Key.empname, element.Key.location, element.Key.kinid, element.Key.managerKin); Console.WriteLine("Enter the details of the Employee.."); Console.ForegroundColor = ConsoleColor.Gray; Console.Write("\nEmployee Name : "); string ename = Console.ReadLine(); Console.Write("Location : "); string elocn = Console.ReadLine(); Console.Write("Employee KinId : "); double ekinid = Convert.ToDouble(Console.ReadLine()); Console.Write("Manager's ID : "); double emngr = Convert.ToDouble(Console.ReadLine()); employee emp1 = new employee(); emp1.empname = ename; emp1.location = elocn; emp1.kinid = ekinid; emp1.managerKin = emngr; int i = 0; // This variable acts as a indicator to find whether the Employee Key exists or not. if (relations.ContainsKey(emp1)) //Put a break point here and see the execution flow. { Console.WriteLine("the Employee : {0} exists..", emp1.empname); Console.WriteLine("the Employee reports to the following manager : {0} \n and the Manager's KinId is {1}.", (relations[emp1]).managername, relations[emp1].kinid); i = 1; Console.ReadLine(); } if (i == 0) { Console.WriteLine("the details of the employee named {0} does not exist !!", emp1.empname); Console.ReadLine(); } #endregion 

要在字典中搜索元素,您可以使用ContainsKey,ContainsValue方法或只编写LINQ查询

 var dict = (from pair in relations where pair.Value.Equals(mng1) select pair).ToDictionary(); 

为了能够比较2个实例的相等性,你应该重写Equals方法,并且实现IEquatable也是一个好习惯。 当您重写Equals时,您还应该覆盖GetHashcode(当您将实例放入字典中以计算存储桶时使用此方法)。

您不应该使用GetHashcode来比较对象的2个实例是否相等; 相反,你应该使用Equals (或EqualityComparer ,它也将使用Equals方法)。

如果您已经实现了GetHashCode和Equals,那么您可以通过执行以下操作来确定字典是否包含特定实例:

 var myDictionary = new Dictionary(); myDictionary.ContainsKey (someKey) 

要么

 var mySet = new HashSet(); mySet.Contains(someManagerObject); 

Dictionary.ContainsKey(employee)在这里没有帮助,因为员工是“未知”值,而Contains将无济于事,因为它需要KeyValuePair并且……再一次……没有员工知道。 ContainsValue(manager)不会帮助,因为它不返回任何键因为它不是键,它是O(n)操作,而不是像ContainsKey这样的O(1)

使用当前结构唯一的方法是使用某种forms的循环,虽然我会这样写:

 // Key is Employee, Value is Manager // This is O(n) var theEmployees = relations .Where(rel => rel.Value.Equals(theManager)) .Select(rel => rel.Key); 

只有在manager获得有效的Equals实施后,这才有效。 请注意, 根本不使用哈希码。 ( 因为不同的对象可能共享相同的哈希代码,所以只比较哈希代码不能替代Equals==CompareTo – 取决于哪一个是合适的。)

如果存在许多这样的查询,则初始结构可以“反转”。

 // Build a reverse lookup-up var employeesForManager = relations .GroupBy(rel => rel.Value) // group on Manager .ToDictionary(g => g.Key, g => g); // Key is the group's Manager // This is O(1), but only valid AFTER employeesForManager is [re-]generated var theEmployees = employeesForManager[theManager] 

这仅在manager具有有效的EqualsGetHashCode实现时才有效。 (GetHashCode是必需的,因为manager对象被用作新词典的键。)

至于哪个是“更好” – 嗯,这取决于。 例如,创建反向查找仅使用一次是愚蠢的。 在出现性能问题之前没有性能问题:编写干净的代码和配置文件。

快乐的编码。

我相信你的最终回复中有一个错误。

这条线

return(obj.GetHashCode()== otheremployee.GetHashCode());

可能应该是

return(this.GetHashCode()== otheremployee.GetHashCode());

这样您就可以比较此对象和其他对象的哈希码。 正如您在回复中所写的那样,您似乎正在将另一个对象与自身进行比较。