C# Sorting using Delegate - c#

I'm new to C# & having trouble wi/ this current assignment. I need to use a Delegate to sort Sort the employees by social security number in descending order and by last name in ascending order. If anyone can just point me in how to get started it will help greatly. This is just the employee class, but if needed, I can post all the classes.
using System;
// Fig. 12.4: Employee.cs
// Employee abstract base class.
using System.Text;
public abstract class Employee : IPayable
{
// read-only property that gets employee's first name
public string FirstName { get; private set; }
// read-only property that gets employee's last name
public string LastName { get; private set; }
// read-only property that gets employee's social security number
public string SocialSecurityNumber { get; private set; }
// three-parameter constructor
public Employee( string first, string last, string ssn )
{
FirstName = first;
LastName = last;
SocialSecurityNumber = ssn;
} // end three-parameter Employee constructor
// return string representation of Employee object, using properties
public override string ToString()
{
return string.Format( "{0} {1}\nsocial security number: {2}",
FirstName, LastName, SocialSecurityNumber );
} // end method ToString
// abstract method overridden by derived classes
public abstract decimal GetPaymentAmount(); // no implementation here
} // end abstract class Employee
// Fig. 12.15: PayableInterfaceTest.cs
// Tests interface IPayable with disparate classes.
using System;
public class PayableInterfaceTest
{
public static void Main( string[] args )
{
// create four-element IPayable array
IPayable[] payableObjects = new IPayable[8];
// populate array with objects that implement IPayable
payableObjects[0] = new SalariedEmployee("John", "Smith", "111-11-1111", 700M);
payableObjects[1] = new SalariedEmployee("Antonio", "Smith", "555-55-5555", 800M);
payableObjects[2] = new SalariedEmployee("Victor", "Smith", "444-44-4444", 600M);
payableObjects[3] = new HourlyEmployee("Karen", "Price", "222-22-2222", 16.75M, 40M);
payableObjects[4] = new HourlyEmployee("Ruben", "Zamora", "666-66-6666", 20.00M, 40M);
payableObjects[5] = new CommissionEmployee("Sue", "Jones", "333-33-3333", 10000M, .06M);
payableObjects[6] = new BasePlusCommissionEmployee("Bob", "Lewis", "777-77-7777", 5000M, .04M, 300M);
payableObjects[7] = new BasePlusCommissionEmployee("Lee", "Duarte", "888-88-888", 5000M, .04M, 300M);
Console.WriteLine(
"Lab 2 output:\n" );
// generically process each element in array payableObjectsWW
foreach ( var currentPayable in payableObjects )
{
// output currentPayable and its appropriate payment amount
Console.WriteLine( "payment due {0}: {1:C}\n",
currentPayable, currentPayable.GetPaymentAmount() );
} // end foreach
} // end Main
} // end class PayableInterfaceTest

Why don't you use LINQ ?
var sortedArray = payableObjects
.OrderByDescending(e => e.SocialSecurityNumber)
.ThenBy(e => e.LastName)
.ToArray();

Array.Sort(T[], delegate int(T, T)) is probably what you're looking for.
Call Array.Sort with your array as the first parameter, and create a function in your Employee that fills delegate int(Employee, Employee). If I recall correctly, that function needs to return 0 if they are equal, a negative number if the first comes first ascending, and a positive number if the first comes second ascending.

//to order by SSN desc
foreach (var e in payableObjects.OrderByDescending(e => e.SocialSecurityNumber))
{
Console.WriteLine(e.FirstName + " " + e.LastName + " " + e.SocialSecurityNumber);
}
Console.WriteLine("");
//to order by Lastname Asc
foreach (var e in payableObjects.OrderBy(e => e.LastName))
{
Console.WriteLine(e.FirstName + " " + e.LastName + " " + e.SocialSecurityNumber);
}

Related

How to use a list<> method in C# VS

I have a question regarding Lists in c# I have a method:
public void example(Employee emp)
Now I need to write
example();
in another method
But when I do it it shows me an error because I need to put something in () but I don't know what or how.
Thanks!
public void SaveToFile(Employee emp)
{
var path2 = Path.Combine(Directory.GetCurrentDirectory(), "text.txt");
File.AppendAllText(path2, emp2 + Environment.NewLine);
}
//ABOVE ME IS THE METHOD I WANNA CALL
//BELOW IS THE START PROGRAM THING (employeedata is another script)
private static void MainMenu(ref EmployeeData employeeData)
{
employeeData.SaveToFile(Employee emp);
}
After all the comments, I guess this is what you need: You must pass one employee object in parameters when calling your void.
Employeee emp = new Employee();
emp.propertyOne = "stuff";
emp.propertyTwo = "more stuff";
example(emp);
You need to pass in a value between the () which are called parameters, because in your method you are asking for an object with the type of Employee. Please check the following url where you can learn more about parameters:
Parameters in C#
What you are missing is a way to convert your Employee object into a string for writing into a file. Use the .ToString() override to do so.
public class Employee
{
public Employee()
{
// Constructor defaults
ID = 0;
Name = string.Empty;
}
public bool IsValid
{
get
{
// Check if ID and Name are set
return ID > 0 && !string.IsNullOrWhiteSpace(Name);
}
}
public int ID { get; set; }
public string Name { get; set; }
public override string ToString()
{
// String representation of an Employee
return $"{ID}, {Name}";
}
}
Then you can have code that reads and writes to files
public static class EmployeeData
{
public static void AppendToFile(string filename, Employee employee)
{
// Use `ToString()` to convert `Employee` to `string`
File.AppendAllText(filename, employee.ToString() + Environment.NewLine);
}
public static Employee Parse(string description)
{
// Take a string of the form "100, John" and split it
// into parts at the comma
string[] parts = description.Trim().Split(',');
Employee emp = new Employee();
if (parts.Length > 0 && int.TryParse(parts[0].Trim(), out int id))
{
// If first part is an integer, assign it to the ID
emp.ID = id;
}
if (parts.Length > 1)
{
// Assign second part to name
emp.Name = parts[1];
}
return emp;
}
public static List<Employee> ReadFromFile(string filename)
{
// Read all text from file as separate lines
List<Employee> list = new List<Employee>();
string[] lines = File.ReadAllLines(filename, Encoding.UTF8);
foreach (var line in lines)
{
// Convert each line of text into an Employee object
Employee emp = Parse(line);
if (emp.IsValid)
{
// If the object is valid add to the list
list.Add(emp);
}
}
return list;
}
}
and the above is used in the following proof of concept code below:
internal class Program
{
static void Main(string[] args)
{
Employee emp1 = new Employee()
{
ID = 1,
Name = "Peter",
};
EmployeeData.AppendToFile("test.txt", emp1);
Employee emp2 = new Employee()
{
ID = 2,
Name = "Maria",
};
EmployeeData.AppendToFile("test.txt", emp2);
List<Employee> employees = EmployeeData.ReadFromFile("test.txt");
foreach (var item in employees)
{
Console.WriteLine(item);
// This calls item.ToString()
}
}
}
which prints the following on the console window the first time its run
1, Peter
2, Maria
Note that each time the program runs it adds to the above creating duplicates. That is a subject of a different question, on how to write an .Equals() function to check for duplicates.

To seed type tables in Entity Framework I want a generic method that takes an enum and creates a list of type objects and Name properties

To seed type tables in Entity Framework Core, I am rewriting this same code in the function 'StopLightColorTypeList' for every database type table that I need seed. I'm looking to create a generic method.
modelBuilder.Entity<StopLightColorType>
().HasData(WLProgramSeed.StopLightColorTypeList());
The StopLightColorTypeList takes each enumeration member creates a new StopLightColorType object and adds it to the list before:
Setting the object ID property to the int value of the Enum
Setting the Name property to the string value of the Enum
I am looking to use generics in such a way where I can
Specify the enumeration type (in this case it's StopLightColorsEnum)
Specify the return type object (in this case it's StopLightColorType)
Specify what property to set for the ID (must be integer) (in this case it's StopLightColorID)
Specify what property to set for the name (must be a string) (in this case it's StopLightColorName)
Optionally specify a function to parse the enumeration name
using System;
using System.Collections.Generic;
using System.Linq;
namespace GenericEnumToTypeList
{
class Program
{
static void Main(string[] args)
{
List<StopLightColorType> stopLightColorTypes = EFTools.StopLightColorTypes();
foreach(var stopLightColorType in stopLightColorTypes)
{
Console.WriteLine("ID: {0} Name: {1}", stopLightColorType.StopLightColorID, stopLightColorType.StopLightColorName);
}
Console.ReadLine();
}
}
public enum StopLightColorsEnum
{
Red = 1,
Yellow = 2,
Green = 3
}
public class StopLightColorType
{
public StopLightColorsEnum StopLightColorID { get; set; }
public string StopLightColorName { get; set; }
}
public class EFTools
{
public static List<StopLightColorType> StopLightColorTypes()
{
List<StopLightColorType> stopLightColorTypes = new List<StopLightColorType>();
foreach(StopLightColorsEnum stopLightColor in System.Enum.GetValues(typeof(StopLightColorsEnum))
{
StopLightColorType stopLightColorType = new StopLightColorType
{
StopLightColorID = stopLightColor,
StopLightColorName = ParseCapitalizedEnumName(stopLightColor.ToString())
};
stopLightColorTypes.Add(stopLightColorType);
}
return stopLightColorTypes;
}
public static string ParseUnderScoreName(string stringName)
{
return stringName.Replace("_", " "); ;
}
public static string ParseCapitalizedEnumName(string enumName)
{
string typeName = enumName[0].ToString();
for(int i = 1; i <= enumName.Length; i++)
{
if(Char.ToUpper(enumName[i]) == enumName[i])
{
typeName = typeName + " " + enumName[i].ToString();
}
}
return typeName;
}
}
}
I re-write this code for each database type, I'm looking for a generic to take care of this operation.
The core function you need is this:
IEnumerable<TResult> ListEnumMembers<TEnum, TResult>(string valueName, string nameName)
where TEnum : System.Enum
{
var enumInfos = Enum.GetValues(typeof(TEnum)).Cast<int>()
.Zip(Enum.GetNames(typeof(TEnum)), (i, s) => (Value: i, Name: s));
var typ = typeof(TResult);
var piValue = typ.GetProperty(valueName);
var piName = typ.GetProperty(nameName);
return enumInfos.Select(i =>
{
var instance = (TResult)Activator.CreateInstance(typ);
piValue.SetValue(instance, i.Value);
piName.SetValue(instance, i.Name);
return instance;
});
}
With this generic result type...
class EnumInfo
{
public int Value { get; set; }
public string Name { get; set; }
}
...and this code:
var enumInfos = ListEnumMembers<DayOfWeek, EnumInfo>("Value", "Name").ToList();
You get this result:
Value
Name
0
Sunday
1
Monday
2
Tuesday
3
Wednesday
4
Thursday
5
Friday
6
Saturday
I guess this will put you on the right track. Of course the code needs a couple of checks for the property names and types.

How to print contents of list instead of type? C# [duplicate]

This question already has answers here:
WriteLine with a class
(9 answers)
Closed 5 years ago.
Probably the title doesn't sound very well for most of you guys (skilled programmers), but I'm on my 3rd week of learning C# fundamentals and I cant figure it out how to solve the next task.
I shall store some temperatures for a bunch of cities, asking a user for a cityName first and then for the actual temp in that city. All this stuff should be saved in a list<> and I shall use Class and Constructor.
When I try to print out the result (using foreach) it prints out the name of my namespace and the name of my class like "Task_5.City"
Whats wrong with my code:
public class City //class
{
public string CityName { get; set; }
public int Temperature { get; set; }
public City(string name, int temp)//konstruktor
{
this.CityName = name;
this.Temperature = temp;
}
}
class Program
{
static void Main(string[] args)
{
var cityList = new List<City>();
Console.WriteLine("What is your city?");
string cityName = Console.ReadLine();
Console.WriteLine("What temperature for this city?");
int temp = Convert.ToInt32(Console.ReadLine());
City myCity = new City(cityName, temp);
cityList.Add(myCity);
foreach (var item in cityList)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
}
You are passing object to the Console.WriteLine(item) instead of passing the string. Console.WriteLine invokes ToString() method of that object that by default returns namespace+class name. You can override this behavior like next:
public class City //class
{
public string CityName { get; set; }
public int Temperature { get; set; }
public City(string name, int temp)//konstruktor
{
this.CityName = name;
this.Temperature = temp;
}
public override string ToString()
{
return string.Format("{0} {1}", CityName, Temperature);
}
}
Or you can use another overload of WriteLine method:
Console.WriteLine("{0} {1}", item.CityName, item.Temperature);
Change Console.WriteLine(item); to one of the following options, if you simply want to write out the contents of your City object.
Console.WriteLine("City: " + item.CityName + " has a temperature of " + item.Temperature + " degrees.");
or, you can use string.Format if you prefer:
Console.WriteLine(string.Format("City: {0} has a temperature of {1} degrees.", item.CityName, item.Temperature));
The item in cityList is of City type, which means that you have properties for CityName and Temperature.
You should use:
Console.WriteLine(item.CityName + " is at " + item.Temperature + ".");
or something similar.
You are using this overload of WriteLine:
public static void WriteLine(object value)
and this overload call ToString method of parameter to produce its string representation. As mentioned Here the default implementation of ToString returns the fully qualified name of the type.
You can override ToString in your City class to be able use instances of this type where a string is expected like Console.WriteLine
public override string ToString()
{
return CityName + Temperature.ToString();
// return $"{CityName} : {Temperature}"; // Or use C# string interpolation
}
Or directly produce required string and pass that to WriteLine method:
Console.WriteLine($"{item.CityName} : {item.Temperature});
Here you are trying to print the object itself. If you would like to print the CityName and Temperature, inside the foreach you have to print the property.
foreach (var item in cityList)
{
Console.WriteLine(item.CityName);
Console.WriteLine(item.Temperature);
}
But here, you are getting a single city and temperature only and printing it. Why do you need a list in that case?

How to Output from Generic Array List, to Listbox?

I am trying to output from Array list to a Listbox. My problem is I think is I do not know how to connect the Class to the Generic array list a made? The end result should look like this:
And the information should be then sorted like so: all the information enters the first list box, and then the above 18 goes to adults, and the below 18 to kids. My class looks like this:
namespace Patients
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public String Password { get; set; }
public Person() //Constructor
{
Age = 0;
Password = "";
}
public Person (string name, int age, string password) //Parameters
{
this.Name = name;
this.Age = age;
this.Password = password;
}
public override string ToString() //
{
return Name + Age.ToString() + Password; //outputs as a string
// return Name + " (" + Age + " years) " + Password ;
}
}
}
namespace Patients
{
public partial class WebForm1 : System.Web.UI.Page
{
public static void Page_Load(object sender, EventArgs e)
{
}
public void ButtonAdd_Click(object sender, EventArgs e)
{
Person p = new Person();
List<string> People = new List<string>();
People.Add(TextBoxName.Text);
People.Add(TextBoxAge.Text);
People.Add(TextBoxPassword.Text);
foreach (object Person in People)
{
ListBoxAll.Items.Add(p.Name + p.Age.ToString() + p.Password);
}
if (p.Age > 18)
{
ListBoxAdults.Items.Add(p.Name + p.Age.ToString() + p.Password);
}
else
{
ListBoxKids.Items.Add(p.Name + p.Age.ToString() + p.Password);
}
}
}
}
I think your problem is, that you don't set the Properties. In Fact you don't need a List at all, but you can use a List to keep hold of your patients. It's still not necessary though:
namespace Patients
{
public partial class WebForm1 : System.Web.UI.Page
{
// Define Property and initialize List
public List<Person> patients{ get; } = new List<Person>();
public static void Page_Load(object sender, EventArgs e)
{
}
public void ButtonAdd_Click(object sender, EventArgs e)
{
// Use the Constructor with Parameters
Person p = new Person(TextBoxName.Text, TextBoxAge.Text, TextBoxPassword.Text);
// Add your patient to your List
patients.Add(p);
// Use the ToString() of your Person
ListBoxAll.Items.Add(p.ToString());
if (p.Age > 18)
{
ListBoxAdults.Items.Add(p.ToString());
}
else
{
ListBoxKids.Items.Add(p.ToString());
}
}
}
}
Looks like you are mixing and matching a bit.
Try something like this.
Person p = new Person();
p.Name = TextBoxName.Text;
p.Age= TextBoxAge.Text;
p.Password= TextBoxPassword.Text;
ListBoxAll.Items.Add(p);
A few tricks that are nice to us, first off you can declare defaults for properties like so:
public string Name { get; set; } = "Steve";
public int Age { get; set; } = 1;
public String Password { get; set; } = "password";
However, it should also be noted that "" is the default for strings already and 0 is the default for non-nullable int, so you don't even need to worrying about those default values.
Declaring Age = 0; in the constructor is basically a waste of time in this case. (If it was a nullable int however the default is null)
Next up, since you are okay with defaults, you don't need to declare properties in the constructor like you are.
You can completely remove the constructor and just do the following:
var myPerson = new Person { Name = "Steve", Age = 18, Password = "Foo" };
Next up, you are losing all your existing people as soon as you exit the scope of the button click.
Instead you'll want to declare two lists of people outside the scope of the click method (that way they persist), something like "Adults" and "Children"
Then perhaps make a method called "PopulateLists" that would do the following:
Clear all list boxes
Add to each box the list of each groups names that apply (you can make an IQueryable by using Linq and Select statements on your list)
When you click the button, you should make a new person, assign it to the right list, then call PopulateLists()
Here's the info you need to get started:
Linq selection to get list of properties (in this case Im going to turn a List of People into a List of Ages, you can do the same with names though)
var ages = People.Select(p => p.Age);
The .Items property of a ListBox works the same as a list, it just visually shows itself. It's a list of strings specifically.
So for example you can do things like...
MyListBox.Items.Clear();
MyListBox.Items.Add(...);
MyListBox.Items.AddRange(...);
etc etc.
That should get you started!

GetHashCode and Equals implementation in Dictionary C#

I came to this site searching for object comparison in Dictionary, and i came to know that overriding GetHashCode and Equals are a must for doing object comparison in C#.
Here is a piece of code that i have been trying to solve out, using FOREACH iteration Method. But my Boss says to do the same without using any iteration(maybe by using containskey or containsvalue method), due to performance issues. Any help is highly welcome..
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<employee, manager> relations = new Dictionary<employee, manager>();
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();
}
}
For searching an object in a dictionary using the ContainsKey or ContainsValue keyword, compiler uses two implicit functions i.e. GetHashCode() and Equals(). So when we have an object for comparison, we need to Override both these methods !!
Here is the code
#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<employee, manager> relations = new Dictionary<employee, manager>();
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
To search element in dictionary you can use ContainsKey, ContainsValue methods or just write LINQ query
var dict = (from pair in relations
where pair.Value.Equals(mng1)
select pair).ToDictionary<employee,manager>();
In order to be able to compare 2 instances for equality, you should override the Equals method and, it is also good practice to implement IEquatable<T>.
When you override Equals, you should also override GetHashcode (this is used when you put your instances in a dictionary to calculate the bucket).
You should not use GetHashcode yourselves in order to compare 2 instances of your object for equality; instead you should use Equals (or an EqualityComparer, which will use the Equals method as well).
If you've implemented GetHashCode and Equals well, then you're able to determine whether a dictionary contains a specific instance by doing:
var myDictionary<int, Manager> = new Dictionary<int,Manager>();
myDictionary.ContainsKey (someKey)
or
var mySet = new HashSet<Manager>();
mySet.Contains(someManagerObject);
Dictionary.ContainsKey(employee) won't help here because the employee is the "unknown" value, and Contains won't help because it takes a KeyValuePair<employee,manager> and ... once again ... no employee is known. ContainsValue(manager) won't help because it doesn't return any key and because it's not a key, it is an O(n) operation, not an O(1) like ContainsKey!
With the current structure the only way is with some form of looping, although I would write it like this:
// Key is Employee, Value is Manager
// This is O(n)
var theEmployees = relations
.Where(rel => rel.Value.Equals(theManager))
.Select(rel => rel.Key);
This will only work after manager is given a valid Equals implementation. Note that the hash code is not used at all. (Because objects that are different may share the same hash-code, just comparing the hash-code is not a replacement for Equals, or ==, or CompareTo! -- depending on which one is appropriate.)
If there will be many such queries then the initial structure can be "inverted".
// 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]
This will only work if manager has a valid Equals and GetHashCode implementation. (GetHashCode is required because manager objects are used the key to the new Dictionary.)
As for which is "better" -- well, that depends. It is silly to create the reverse-lookup to only use it once, for instance. There is no performance problem until there is a performance problem: write clean code and profile.
Happy coding.
I believe you have a bug in your final response.
The line
return (obj.GetHashCode() == otheremployee.GetHashCode());
Probably should be
return (this.GetHashCode() == otheremployee.GetHashCode());
That way you are comparing the hash code for this object and the other object. As it is written in your response you appear to be comparing the other object to itself.

Categories