How can I use Equals or hashcode in my following program - c#

I want to fetch the details of manager from manager class if at run time I give kinid of employee from the employee class. How can I do this using Equals or Hashcode?
public class employee
{
public string empname { get; set;}
public string location { get; set; }
public int kinid { get; set; }
public double magkin { get; set; }
}
public class manager
{
public string magname { get; set; }
public double magkin { get; set; }
}
Dictionary<employee, manager> relation = new Dictionary<employee, manager>();

I haven't used C# in a long time, but Something like this should work:
kinidFind is the kinid you want to search for.
manager findManager(int kinidFind) {
foreach( KeyValuePair<employee, manager> i in relation) {
if (i.Key.kinid==kinidFind) {
return i.Value;
}
}
}

Assuming that kinid is a unique identifier (you don't care about other fields of employee in identifying), then on employee class you could do the following:
override int GetHashCode()
{
return kinid;
}
override bool Equals(Object obj)
{
if (obj == null) return false;
emploee emp = obj as employee;
if ((System.Object)emp == null) return false;
return (kinid == emp.kinid);
}
However, this is not a good general solution because what if later on you want to find the employee by other fields?
Consider changing that dictionary to:
Dictionary<int,manager> where the int is the kinid of the employee then it's self explanatory.

or since the Dictionary has been loaded you can Enumerate it this way as well it's just a question of feel or taste at this point from Brads answer
foreach (var pair in relation)
{
if (pair.key == kinidFind )
{
return relation[pair.key];
}
}

Related

How to check if item is already in list in repository?

Ok, so there are a few excepotions here, I cannot use List<Dvd> Dvds = _dvds.ReadAll(); in DvdController.cs and check to see if it contains the dvd info if dvd is already in the list. Even if I did do that, it does not work as I intended it to do. Even if I check to see if the info is in the list and try to stop it, it still adds it to a list. The Dvd.cs does increment the Id by one by the way. I would like to know what would be the solution to this?
DvdController.cs
...
private void CreateDvd() //Create
{
var myView = new DvdView();
var dvdInfos = myView.GetNewDvdInfo();
_dvds.Create(dvdInfos);
DisplayDvds();
}
...
DvdRepository.cs
public class DvdRepository
{
private static List<Dvd> dvds = new List<Dvd>()
{
new Dvd("Batman", 2010, "Bruce", 4 ),
new Dvd("Superman", 2009, "John", 4),
new Dvd("Wonderwoman", 2012, "Omar", 4)
};
public Dvd Create(Dvd dvd)
{
if (dvds.Contains(dvd))
{
Console.WriteLine("duplicate"); //not working
}
else
dvds.Add(dvd);
return dvds.FirstOrDefault(d => d.Id == dvd.Id);
}
public List<Dvd> ReadAll()
{
return dvds;
}
...
Dvd.cs
public class Dvd
{
public Dvd(string title, int releaseyear, string director, float rating)
{
Id = Interlocked.Increment(ref globalId);
Title = title;
ReleaseYear = releaseyear;
Director = director;
Rating = rating;
}
public static int globalId;
public int Id { get; private set; }
public string Title { get; set; }
public int ReleaseYear { get; set; }
public string Director { get; set; }
public float Rating { get; set; }
Your check of if (dvds.Contains(dvd)) is looking for that specific object reference. Unless you pass in the actual object that is in the list already, it won't work.
You need to check a unique identifying property of the Dvd. For this you would want to use the .Any() method.
if (dvds.Any(x => x.Title == dvd.Title))
Another solution that requires a bit more code upfront but will likely help in other scenarios in the future is to override the Equals and GetHashCode methods on the Dvd class. By default, objects use a reference comparison to determine equality. By overriding these methods, we can use our own logic to determine if two Dvds are equal.
In the example below, I'm using the fields Title, ReleaseYear, and Director, but you could add others as you see fit. I also implemented IEquatable<Dvd> because it's pretty simple (just requires adding an Equals method that takes an object of type Dvd) and it goes along well with the object.Equals implementation:
public class Dvd : IEquatable<Dvd>
{
public Dvd(string title, int releaseyear, string director, float rating)
{
Id = Interlocked.Increment(ref globalId);
Title = title;
ReleaseYear = releaseyear;
Director = director;
Rating = rating;
}
public static int globalId;
public int Id { get; private set; }
public string Title { get; set; }
public int ReleaseYear { get; set; }
public string Director { get; set; }
public float Rating { get; set; }
public bool Equals(Dvd other)
{
return other != null &&
Title == other.Title &&
ReleaseYear == other.ReleaseYear &&
Director == other.Director;
}
public override bool Equals(object obj)
{
return Equals(obj as Dvd);
}
public override int GetHashCode()
{
return ((Title?.GetHashCode() ?? 17) * 17 +
ReleaseYear.GetHashCode()) * 17 +
(Director?.GetHashCode() ?? 17);
}
}
With these changes in place, we don't have to worry about remembering which fields we need to compare when evaluating two Dvd objects in a Linq query (and if we want to add more properties for comparison, we just do it in one place rather than searching throughout our code), and we can do things like if (firstDvd.Equals(secondDvd)) { // do something if they're equal } .
Now we can use the Contains method as defined in your original code. For example:
private static void Main()
{
var repo = new DvdRepository();
repo.Create(new Dvd("Batman", 2010, "Bruce", 2));
}
Outputs to the console: "duplicate"

LINQ Check ObservableCollection doesn't contain matching Object

Trying to check that my ObservableCollection doesn't have an object matching the one i'm trying to add.
For example:
public class LoggedUsers : NotifyUIBase
{
public ObservableCollection<Logged> UserList { get; private set; }
public LoggedUsers()
{
UserList = new ObservableCollection<Logged>();
}
public void Add(Logged user)
{
if (UserList.Where(x => x == user))
{
UserList.Add(user);
}
}
}
So if the ObservableCollection has got a Logged object with the same property values as the Add(Logged user) then I want it to not add the user.
Edit 1:
public class LoggedUsers : NotifyUIBase
{
public ObservableCollection<Logged> UserList { get; private set; }
public LoggedUsers()
{
UserList = new ObservableCollection<Logged>();
}
public void Add(Logged user)
{
if (!UserList.Any(x => x == user))
{
UserList.Add(user);
////Check the List for users
UpdateView();
}
else
{
MessageBox.Show("Already exists!");
}
}
Edit 2:
Changed my Logged class to the following:
namespace PhotoManagement
{
public class Logged : Common.NotifyUIBase
{
public string ClearPassword { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public long UID { get; set; }
public string Email { get; set; }
//Display basic statistics
public int ThisDayImageCount { get; set; }
public int ThisDaySaleCount { get; set; }
public Logged()
{
//Update the stats when instigated
UpdateStats();
}
//Update the stats
public void UpdateStats()
{
}
public bool Equals(Logged other)
{
if (other == null) return false;
return (this.UID.Equals(other.UID));
}
}
}
So this should work? However it still says Already Exists when I have checked the instances and they are different.
public class LoggedUsers : NotifyUIBase
{
public ObservableCollection<Logged> UserList { get; private set; }
public LoggedUsers()
{
UserList = new ObservableCollection<Logged>();
}
public void Add(Logged user)
{
if (!UserList.Any(x => x.Equals(user)))
{
UserList.Add(user);
UpdateView();
}
else
{
MessageBox.Show("Already exists!");
}
}
The best solution is to implement IEquatable as said #vadim-martynov.
Another fast but no so clean solution is to search by explicitly comparing values:
public void Add(Logged user)
{
if (!UserList.Any(x => x.Id == user.Id && x.UserName == user.UserName))
{
UserList.Add(user);
////Check the List for users
UpdateView();
}
else
{
MessageBox.Show("Already exists!");
}
}
Edit 1:
Think about your Logged class. The key here is to implement the IEquatable interface who implement Equals method. There should you implement the explicitly comparing you will apply then we call Equals on this class.
public class Logged: IEquatable<Logged>
{
public int Id { get; set; }
public string UserName { get; set; }
public string OtherProperty { get; set; }
public bool Equals(Logged other)
{
return this.Id == other.Id && this.UserName == other.UserName;
}
}
After you Add method will look like:
public void Add(Logged user)
{
if (!UserList.Any(x => x.Equals(user)))
{
UserList.Add(user);
////Check the List for users
UpdateView();
}
else
{
MessageBox.Show("Already exists!");
}
}
Edit 2:
Ok, then we must try a planb. Try implementing IComparable and try using with this. IEquatable should work but if not, this could work too.
public class Logged: IEquatable<Logged>, IComparable<Logged>
{
public int Id { get; set; }
public string UserName { get; set; }
public string OtherProperty { get; set; }
public bool Equals(Logged other)
{
return this.Id == other.Id && this.UserName == other.UserName;
}
public int CompareTo(Logged other)
{
return this.Id.CompareTo(other.Id);
}
}
IComparable returns int. So the usage and integer result are:
var result = x.CompareTo(user)
// Comparing 'some text' with '123': 1
// Comparing 'some text' with 'some text': 0
// Comparing 'some text' with 'Some Text': -1
Try to specify the attribute in the query to find match, ex. Username or User ID.
public void Add(Logged user)
{
if (!UserList.Any(u => u.Username == user.Username))
{
UserList.Add(user);
}
}
By default your object compared by reference via == operator. It's common feature of reference types in c#.
You can override this operator or override Equals method.
The new implementation of Equals should not throw exceptions. It is
recommended that any class that overrides Equals also override
System.Object.GetHashCode. It is also recommended that in addition to
implementing Equals(object), any class also implement Equals(type) for
their own type, to enhance performance.
Also, you can implement IEquatable<T> for your Logged class.
To avoid having different results depending on the way you check the
equality of the objects, you should override the Object.Equals method
in your class. This ensures that whenever a class doesn't use
the IEquatable.Equals method, still the same checks will be performed.
Finally you can compare some properties of 2 instances inside Where method:
if(!UserList.Any(u => u.Login == user.Login))
{
UserList.Add(user);
}

Comparing two complex objects, one from DB and one from input

I have a program that takes in a file, does some data crunching and then compares the result with what is in the DB.
Object
public class ReleaseDates
{
public int Id { get; set; }
public string MovieName { get; set; }
public string Country { get; set; }
public DateTime ReleaseDate { get; set; }
public string AlternateSource { get; set; }
}
It is very likely that the MovieName will be the same as what is in the DB but the ReleaseDate could change.
How can I compare what I grab from the DB to a ReleaseDate object list?
Example
public bool Compare(ReleaseDates original, ReleaseDates newObj)
{
if (original.AlternateSource != newDate.AlternateSource)
{
return false;
}
if (original.Country != newDate.Country)
{
return false;
}
if (original.MovieName != newDate.MovieName)
{
return false;
}
if (original.ReleaseDate != newDate.ReleaseDate)
{
return false;
}
return true;
}
How I am getting the data from the DB:
public List<ReleaseDates> GetAllReleaseDates()
{
return Db.ReleaseDates.ToList(); // Db is my DataContext
}
The above example is to compare for a single instance of ReleaseDates, but how can I compare a list? I cannot order the List since there will be duplicates with the same MovieName but different ReleaseDate and AlternateSource.
Update
Sorry I have asked the wrong question.
What I want to do is compare the DB list with the new list and if they are different, remove it from the DB and insert the new item.
E.g.
public void Example(ReleaseDates A, ReleaseDates B)
{
if(A.MovieName != B.MovieName) // But need to compare all properties
{
Db.ReleaseDates.Remove(A);
Db.ReleaseDates.Add(B);
Db.SaveChanges();
}
}
public bool Compare(List<ReleaseDates> A, List<ReleaseDates> B)
{
if ( A.Count != B.Count ) return false;
foreach (ReleaseDates aElement in A)
{
if ( !B.Any ( bElement => Compare( aElement, bElement ) return false;
}
}
It would be better if you treat your collections as sets. You can override the equals method of ReleaseDates class (I feel Movie is a better name for this class) and add the elements of each collection to a HashSet.
You can use HashSet.SetEquals method to check for equality.

c# Check if custom class is in list<t>

I have a list of custom class called List<Notifications>.
The class is below:
public class Notification
{
public enum Type {
Promotion,
Other
}
public string ID { get; set; }
public string Headline { get; set; }
public string Detail { get; set; }
public Type NotificationType { get; set; }
}
Before adding an instance of the Notification class to my custom list, I want to check if it is already in the list.
What is the best way to achieve this?
You can use 1.) Contains, but then you have to override Equals (+ GethashCode).
bool contains = list.Contains(someNotificationInstance);
For example:
public class Notification
{
public enum Type {
Promotion,
Other
}
public string ID { get; set; }
public string Headline { get; set; }
public string Detail { get; set; }
public Type NotificationType { get; set; }
public override bool Equals(object obj)
{
return obj is Notification && string.Equals(ID, ((Notification)obj).ID);
}
public override int GetHashCode()
{
return ID == null ? 0 : ID.GetHashCode();
}
}
2.) another option is to provide a custom IEqualityComparer<Notification> for Contains:
public class NotificationComparer : IEqualityComparer<Notification>
{
public bool Equals(Notification x, Notification y)
{
return x.ID == y.ID;
}
public int GetHashCode(Notification obj)
{
return obj.ID == null ? 0 : obj.ID.GetHashCode();
}
}
On this way you don't need to modify the original class. You can use it in this way:
bool contains = list.Contains(someInstance, new NotificationComparer());
3.) Probably the easiest approach is using Enumerable.Any:
bool contains = list.Any(n => someInstance.ID == n.ID);
4.) The most efficient approach is using a set if no duplicates are allowed in the collection anyway. Then you can use the first or second approaches for a HashSet<T>:
var set = new HashSet<Notification>(new NotificationComparer());
set.Add(instance1);
bool contains = !set.Add(instance2);
You can check it with Contains method.
if (!mylist.Select(l => l.ID).Contains(mynewid)) {
var item = new Notifcation();
item.ID = mynewid;
item..... // fill the rest
mylist.Add(item);
}
Maybe a better approch would be use of Dictionary.

How to perform LINQ on IEnumerable<Employee> / IEnumerable<object>?

I have
IEnumerable<Employee> GetAllEmployees()
{
return Get<IEmployeeRepository>().GetAll();
}
Where IEmployeeRepository is
public interface IEmployeeRepository
{
IEnumerable<Employee> GetAll();
}
Employee.cs is as under
public class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; }
public int Age { get; set; }
public int Salary { get; set; }
}
Now I want to perform a search on the records obtained from GetAllEmployees() based on the EmployeeId passed. Like as under
public void SearchEmployee(int empId)
{
var empRecords = this.GetAllEmployees();
var filteredRecords = empRecords.
}
I actually looked into this answer but could not fit into the requirement.
What I need to do?
I just figured out that the namespace System.Linq is missing.
Else we could even do
foreach (var item in empRecords)
{
//
}
I will give the credit to # Jenish Rabadiya, though others have also given correct opinion.
This is the object first you need to convert to list of object and then try to cast it.
(empRecords as IEnumerable<object>).Cast(....)

Categories

Resources