C# class definition HELP - c#

This is a project question that i just cant seem to answer
using System;
namespace ConsoleApplication2
{
internal class Equipment : IComparable
{
private readonly string type;
private readonly int serialNo;
private string colour;
public decimal cost;
public Equipment(string type, int serialNo)
{
this.type = type == null ? "" : type.Trim();
this.serialNo = serialNo;
}
public string Key
{
get { return type + ":" + serialNo; }
}
int IComparable.CompareTo(object obj)
{
return 0;
}
}
}
(a) Override the appropriate method o ensure that different instances of the class that represent the same equipment item will be considered the same in the system.
(b) Override the appropriate method to enable instances of this class to be stored (and found) by key in a hash table

You should override the Equals and GetHashCode methods for this purpose.

Override Equals() with an appropriate logic of comparision
Override GetHashCode(), see GetHashCode Guidelines in C#
You must start reading this before doing such a task
Why is it important to override GetHashCode when Equals method is overriden in C#?

Writing GetHashCode manually is not that easy. Anyhow, that's code generated for this purpose by ReSharper. It's a complete solution. (It should be contained within your class definition of course). But what would you say, if you were asked - why and how it works? It might be embarassing.
So, apart from GetHashCode and Equals, which others have suggested you reading about, you might also look up http://msdn.microsoft.com/en-us/library/system.object.referenceequals.aspx as well as http://msdn.microsoft.com/en-us/library/a569z7k8(v=VS.100).aspx
As for the mystery behind 397 in GetHashCode, have a look at this question here on StackOverflow: Why is '397' used for ReSharper GetHashCode override?
public bool Equals(Equipment other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Equals(other.colour, colour) && other.cost == cost && other.serialNo == serialNo && Equals(other.type, type);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != typeof (Equipment))
{
return false;
}
return Equals((Equipment) obj);
}
// note: if "Override the appropriate method to enable instances of this class
// to be stored (and found) by key in a hash table" is supposed to mean that only type and
// serialNo should be taken into account (since they are used to generate
// the Key value) - just remove the lines with cost and colour
public override int GetHashCode()
{
unchecked
{
int result = (colour != null ? colour.GetHashCode() : 0);
result = (result*397) ^ cost.GetHashCode();
result = (result*397) ^ serialNo;
result = (result*397) ^ (type != null ? type.GetHashCode() : 0);
return result;
}
}

Related

Trouble with generics using custom equality comparison [duplicate]

This question already has answers here:
IEquatable, how to implement this properly [duplicate]
(2 answers)
Closed 2 years ago.
I have a class heirarchy as follows:
public abstract class Issue
{
// some base properties
// these are not included in equality checks for deriving classes
// also not performing equality checks on this base class (it is abstract anyway)
}
public class IssueTypeA : Issue, IEquatable<IssueTypeA>
{
// some properties specific to this class
// these are the two for which equality comparison is performed
public string requirement { get; set; }
public string preamble { get; set; }
public bool Equals(IssueTypeA that)
{
// determine based on the values of the properties
// they must both be the same for equality
if ((this.requirement.Equals(that.requirement)) &&
(this.preamble.Equals(that.preamble)))
{
return true;
}
return false;
}
}
public class IssueTypeB : Issue, IEquatable<IssueTypeB>
{
// some properties specific to this class
public bool Equals(IssueTypeB that)
{
// determine based on the values of the properties
}
}
There is another class, intended to receive objects in the above heirarchy (except the base class, of course), and do some comparison operations with them:
public class Comparer<T> where T : Issue
{
// various comparison methods
public IEnumerable<T> getReferenceChangedIssues(IEnumerable<T> spreadsheetIssues, IEnumerable<T> downloadedIssues)
{
foreach (T spreadsheetRecord in T spreadsheetIssues)
{
foreach (T downloadedIssue in downloadedIssues)
{
// this is the point of failure
// there are cases in which this should be true, but it is not
if (spreadsheetRecord.Equals(downloadedIssue))
{
// the referenceChanged method works fine by itself
// it has been unit tested
if (spreadsheetRecord.referenceChanged(downloadedIssue))
yield return spreadsheetRecord;
}
}
}
}
}
Through unit testing and debugging, it's apparent that the custom Equals methods defined above are not being used correctly by Comparer. Why is this? It is also intended to include methods with some set operations in the future, which will need Equals.
When you implement IEquatable, you really need to override bool Equals(object) and GetHashCode. If you don't do that, things will break in weird ways. This was the stripped-down-est thing I could come up with. I think it should solve your issue (but I can't really tell without your comparison code). If folks point out issues, I'll fix up the code:
public abstract class Issue : IEquatable<Issue>
{
// possibly (not not necessarily) some base properties
// if they are included, make them part of the equality comparison and
// include them in the HashCode calculations
public bool Equals(Issue other)
{
if (other == null)
{
return false;
}
if (this.GetType() != other.GetType())
{
return false;
}
//test local properties and return true/false based on their values
return true;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Issue) obj);
}
}
public class IssueTypeA : Issue, IEquatable<IssueTypeA>
{
public string AName { get; set; } = "My A Name";
public int AValue { get; set; } = 42;
public bool Equals(IssueTypeA other)
{
if (!base.Equals(other))
{
return false;
}
return AName == other.AName && AValue == other.AValue;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((IssueTypeA) obj);
}
//hash-codes need to be consistent once they are calculated - jump through some hoops
private int? _hashCodeValue = default;
public override int GetHashCode()
{
if (!_hashCodeValue.HasValue)
{
_hashCodeValue = $"{AName}{AValue}".GetHashCode();
}
return _hashCodeValue.Value;
}
}
public class IssueTypeB : Issue, IEquatable<IssueTypeB>
{
// some properties specific to this class
public string BName { get; set; } = "My B Name";
public int BValue { get; set; } = 84;
public bool Equals(IssueTypeB other)
{
if (!base.Equals(other))
{
return false;
}
//calculate equality based on local properties and return true/false
return BName == other.BName && BValue == other.BValue;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((IssueTypeB) obj);
}
//hash-codes need to be consistent once they are calculated - jump through some hoops
private int? _hashCodeValue = default;
public override int GetHashCode()
{
if (!_hashCodeValue.HasValue)
{
_hashCodeValue = $"{BName}{BValue}".GetHashCode();
}
return _hashCodeValue.Value;
}
}
This is a better stab at a solution than the first pass. I check for equality based on properties local to each class. I also provide a GetHashCode implementation that is consistent (in the weird way that I believe GetHashCode requires - but in a way that drive Resharper nuts).

C# list of custom class .Contains()

i have a list of custom class and before adding to the list i want to check if the list has the same instance (not one attribute - all of them)
public class Function
{
public string Name;
public string RT;
public int ParamCount;
public List<string> ParamDT;
public Function()
{
ParamDT = new List<string>();
}
}
i tried overriding Equals() and GetHashCode()
but it didn't work
Equals()
public override bool Equals(object obj)
{
var item = obj as Function;
if (item == null)
{
return false;
}
return this.Name == item.Name && this.RT == item.RT &&
this.ParamCount == item.ParamCount && this.ParamDT.Equals(item.ParamDT);
}
GetHashCode()
public override int GetHashCode()
{
return this.Name.GetHashCode();
}
ParamDT is also a list, you have to check its items also individually to compare properly.
this.ParamDT.Equals(item.ParamDT);
Having said that, list is not the structure you should be using if you want single instances of your object. There is a lot of overhead trying to search for equality in list as you will be searching the entire list. Try to use a set/dictionary based structure.
Your implementation of GetHasCode function is also not proper. It is based only on Name property while in equality you are using all the properties, this will lead to undesirable characteristics. Please read the MSDN documentation for a better implementation.
A simple Equals and GetHashCode is below:
protected bool Equals(Function other)
{
return string.Equals(Name, other.Name) && string.Equals(RT, other.RT) && ParamCount == other.ParamCount && Equals(ParamDT, other.ParamDT);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Function) obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = (Name != null ? Name.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (RT != null ? RT.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ ParamCount;
hashCode = (hashCode * 397) ^ (ParamDT != null ? ParamDT.GetHashCode() : 0);
return hashCode;
}
}
you can then use a HashSet which is a collection that contains no duplicate elements. This will ensure there is no code written for checking uniqueness in List. Link is here: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1?redirectedfrom=MSDN&view=netframework-4.7.2

How to check if list contains item [duplicate]

Why does this program print "not added" while I think it should print "added"?
using System;
using System.Collections.Generic;
class Element
{
public int id;
public Element(int id)
{
this.id = id;
}
public static implicit operator Element(int d)
{
Element ret = new Element(d);
return ret;
}
public static bool operator ==(Element e1, Element e2)
{
return (e1.id == e2.id);
}
public static bool operator !=(Element e1, Element e2)
{
return !(e1.id == e2.id);
}
}
class MainClass
{
public static void Main(string[] args)
{
List<Element> element = new List<Element>();
element.Add(2);
if(element.Contains(2))
Console.WriteLine("added");
else
Console.WriteLine("not added");
}
}
The Contains method does not use the == operator‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌. What is the problem?
The Contains method does not use the == operator‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌
No - it uses Equals, which you haven't overridden... so you're getting the default behaviour of Equals, which is to check for reference identity instead. You should override Equals(object) and GetHashCode to be consistent with each other - and for sanity's sake, consistent with your == overload too.
I'd also recommend implementing IEquatable<Element>, which List<Element> will use in preference to Equals(object), as EqualityComparer<T>.Default picks it up appropriately.
Oh, and your operator overloads should handle null references, too.
I'd also strongly recommend using private fields instead of public ones, and making your type immutable - seal it and make id readonly. Implementing equality for mutable types can lead to odd situations. For example:
Dictionary<Element, string> dictionary = new Dictionary<Element, string>();
Element x = new Element(10);
dictionary[x] = "foo";
x.id = 100;
Console.WriteLine(dictionary[x]); // No such element!
This would happen because the hash code would change (at least under most implementations), so the hash table underlying the dictionary wouldn't be able to find even a reference to the same object that's already in there.
So your class would look something like this:
internal sealed class Element : IEquatable<Element>
{
private readonly int id;
public int Id { get { return id; } }
public Element(int id)
{
this.id = id;
}
public static implicit operator Element(int d)
{
return new Element(d);
}
public static bool operator ==(Element e1, Element e2)
{
if (object.ReferenceEquals(e1, e2))
{
return true;
}
if (object.ReferenceEquals(e1, null) ||
object.ReferenceEquals(e2, null))
{
return false;
}
return e1.id == e2.id;
}
public static bool operator !=(Element e1, Element e2)
{
// Delegate...
return !(e1 == e2);
}
public bool Equals(Element other)
{
return this == other;
}
public override int GetHashCode()
{
return id;
}
public override bool Equals(object obj)
{
// Delegate...
return Equals(obj as Element);
}
}
(I'm not sure about the merit of the implicit conversion, by the way - I typically stay away from those, myself.)
The Contains method does not use the == operator‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌. What is the problem?
That is correct.
This method [Contains] determines equality by using the default equality comparer, as defined by the object's implementation of the IEquatable.Equals method for T (the type of values in the list).
http://msdn.microsoft.com/en-us/library/bhkz42b3(v=vs.110).aspx
You need to override Equals() as well. Note when you overload Equals(), it is almost always correct to also override GetHashCode().
Override Equals and GetHashCode like:
class Element
{
public int id;
protected bool Equals(Element other)
{
return id == other.id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Element) obj);
}
public override int GetHashCode()
{
return id; //or id.GetHashCode();
}
//..... rest of the class
See: List<T>.Contains Method
This method determines equality by using the default equality
comparer, as defined by the object's implementation of the
IEquatable<T>.Equals method for T (the type of values in the list).

Why doesn't List.Contains work as I expect?

Why does this program print "not added" while I think it should print "added"?
using System;
using System.Collections.Generic;
class Element
{
public int id;
public Element(int id)
{
this.id = id;
}
public static implicit operator Element(int d)
{
Element ret = new Element(d);
return ret;
}
public static bool operator ==(Element e1, Element e2)
{
return (e1.id == e2.id);
}
public static bool operator !=(Element e1, Element e2)
{
return !(e1.id == e2.id);
}
}
class MainClass
{
public static void Main(string[] args)
{
List<Element> element = new List<Element>();
element.Add(2);
if(element.Contains(2))
Console.WriteLine("added");
else
Console.WriteLine("not added");
}
}
The Contains method does not use the == operator‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌. What is the problem?
The Contains method does not use the == operator‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌
No - it uses Equals, which you haven't overridden... so you're getting the default behaviour of Equals, which is to check for reference identity instead. You should override Equals(object) and GetHashCode to be consistent with each other - and for sanity's sake, consistent with your == overload too.
I'd also recommend implementing IEquatable<Element>, which List<Element> will use in preference to Equals(object), as EqualityComparer<T>.Default picks it up appropriately.
Oh, and your operator overloads should handle null references, too.
I'd also strongly recommend using private fields instead of public ones, and making your type immutable - seal it and make id readonly. Implementing equality for mutable types can lead to odd situations. For example:
Dictionary<Element, string> dictionary = new Dictionary<Element, string>();
Element x = new Element(10);
dictionary[x] = "foo";
x.id = 100;
Console.WriteLine(dictionary[x]); // No such element!
This would happen because the hash code would change (at least under most implementations), so the hash table underlying the dictionary wouldn't be able to find even a reference to the same object that's already in there.
So your class would look something like this:
internal sealed class Element : IEquatable<Element>
{
private readonly int id;
public int Id { get { return id; } }
public Element(int id)
{
this.id = id;
}
public static implicit operator Element(int d)
{
return new Element(d);
}
public static bool operator ==(Element e1, Element e2)
{
if (object.ReferenceEquals(e1, e2))
{
return true;
}
if (object.ReferenceEquals(e1, null) ||
object.ReferenceEquals(e2, null))
{
return false;
}
return e1.id == e2.id;
}
public static bool operator !=(Element e1, Element e2)
{
// Delegate...
return !(e1 == e2);
}
public bool Equals(Element other)
{
return this == other;
}
public override int GetHashCode()
{
return id;
}
public override bool Equals(object obj)
{
// Delegate...
return Equals(obj as Element);
}
}
(I'm not sure about the merit of the implicit conversion, by the way - I typically stay away from those, myself.)
The Contains method does not use the == operator‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌. What is the problem?
That is correct.
This method [Contains] determines equality by using the default equality comparer, as defined by the object's implementation of the IEquatable.Equals method for T (the type of values in the list).
http://msdn.microsoft.com/en-us/library/bhkz42b3(v=vs.110).aspx
You need to override Equals() as well. Note when you overload Equals(), it is almost always correct to also override GetHashCode().
Override Equals and GetHashCode like:
class Element
{
public int id;
protected bool Equals(Element other)
{
return id == other.id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Element) obj);
}
public override int GetHashCode()
{
return id; //or id.GetHashCode();
}
//..... rest of the class
See: List<T>.Contains Method
This method determines equality by using the default equality
comparer, as defined by the object's implementation of the
IEquatable<T>.Equals method for T (the type of values in the list).

how to implement override of GetHashCode() with logic of overriden Equals()

I have some classes as below, i have implemented the Equals(Object) method for almost all of them. But i don't know how to write GetHashCode() . As far I used these data types as value type in a Dictionary Collection, i think i should override GetHashCode().
1.I don't know how to implement GetHashCode() with logic of Equals(Object).
2.There are some derived classes, if i override GetHashCode() and Equals(Object) for base class ( Param ), is it still necessary to override it for childs?
class Param
{
...
public Int16 id { get; set; }
public String name { get; set; }
...
public override bool Equals(object obj)
{
if ( obj is Param){
Param p = (Param)(obj);
if (id > 0 && p.id > 0)
return (id == p.id);
else if (name != String.Empty && p.name != String.Empty)
return (name.equals(p.name));
else
return object.ReferenceEquals(this, obj);
}
return false;
}
}
class Item
{
public int it_code { get; set; }
public Dictionary<String, Param> paramAr { get; set; }
...
public override bool Equals(Object obj)
{
Item im = new Item();
if (obj is Item)
im = (Item)obj;
else
return false;
if (this.it_code != String.Empty && im.it_code != String.Empty)
if (this.it_code.Equals(im.it_code))
return true;
bool reParams = true;
foreach ( KeyValuePair<String,Param> kvp in paramAr ){
if (kvp.Value != im.paramAr[kvp.Key]) {
reParams = false;
break;
}
}
return reParams;
}
}
class Order
{
public String or_code { get; set; }
public List <Item> items { get; set; }
...
public override bool Equals( Object obj ){
Order o = new Order();
if (obj is Order)
o = (Order)obj;
else
return false;
if (this.or_code != String.Empty && o.or_code != String.Empty)
if (this.or_code.Equals(o.or_code))
return true;
bool flag = true;
foreach( Item i in items){
if (!o.items.Contains(i)) {
flag = false;
break;
}
}
return flag;
}
}
EDIT:
i get this warning:
Warning : 'Item' overrides Object.Equals(object o) but does not
override Object.GetHashCode()
Firstly, as I think you understand, wherever you implement Equals you MUST also implement GetHashCode. The implementation of GetHashCode must reflect the behaviour of the Equals implementation but it doesn't usually use it.
See http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx - especially the "Notes to Implementers"
So if you take your example of the Item implementation of Equals, you're considering both the values of id and name to affect equality. So both of these must contribute to the GetHashCode implementation.
An example of how you could implement GetHashCode for Item would be along the lines of the following (note you may need to make it resilient to a nullable name field):
public override GetHashCode()
{
return id.GetHashCode() ^ name.GetHashCode();
}
See Eric Lippert's blog post on guidelines for GetHashCode - http://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/
As for whether you need to re-implement GetHashCode in subclasses - Yes if you also override Equals - as per the first (and main) point - the implementation of the two must be consistent - if two items are considered equal by Equals then they must return the same value from GetHashCode.
Side note:
As a performance improvement on your code (avoid multiple casts):
if ( obj is Param){
Param p = (Param)(obj);
Param p = obj as Param;
if (p != null) ...
I prefer Josh Bloch's aproach.
Here's the example for the Param class.
override GetHashCode(object obj)
{
unchecked
{
int hash = 17;
hash = hash * 23 + id.GetHashCode();
hash = hash * 23 + name.GetHashCode();
return hash;
}
}
Also, check this link out : .net - best algorithm for GetHashCode
Properties used for the hashcode computation should be immutable as well.

Categories