C# - Any Code optimization technique for Overriding "Equals"? - c#

Normally ( Based on my understanding ) i have to follow a lot of steps to
override the "Equals" to check the state of the object.
Example :
public override bool Equals(object obj)
{
if (obj is SalesPerson && obj != null)
{
SalesPerson temp;
temp = (SalesPerson)obj;
if (temp.fName == this.fName && temp.lName == this.fName
&& temp.personAge == this.personAge )
{
return true;
}
else
{
return false;
}
}
return false;
}
Any other alternative like LINQ or other techniques gives me shortcut code ?
Update :
Moreover i gusess i have to override GetHasCode() too when i override "Equals".

All the answers so far seem mostly fine to me. However, you should carefully consider what you want equality to mean in an inheritance hierarchy. Can an instance of just SalesPerson be equal to an instance of SalesManager (which would derive from SalesPerson)?
The trouble is, the symmetric nature of equals gets in the way. Suppose we have:
SalesPerson x = new SalesPerson { ... };
SalesManager y = new SalesManager { ... };
I'd expect y.Equals(x) to be false - which means that x.Equals(y) ought to be false too.
This means the check in SalesPerson really needs to be:
public override bool Equals(object obj)
{
SalesPerson salesPerson = obj as SalePerson;
if (salesPerson == null) return false;
return salesPerson.GetType() == this.GetType() &&
salesPerson.fName == this.fName &&
salesPerson.lName == this.fName &&
salesPerson.personAge == this.personAge;
}
Note that I'm not comparing with typeof(SalesPerson) as the implementation in SalesManager would probably want to call up to this implementation first.
Of course, all of this complication goes away if SalesPerson is sealed... another reason for being very careful before introducing inheritance :)

This looks neater:
public override bool Equals(object obj)
{
SalesPerson salesPerson = obj as SalePerson;
if(salesPerson == null) return false;
return salesPerson.fName == this.fName &&
salesPerson.lName == this.fName &&
salesPerson.personAge == this.personAge;
}

And of course if you really wanted to compact it into a single line you could use:
public override bool Equals(object obj)
{
SalesPerson salesPerson = obj as SalePerson;
return (salesPerson != null) &&
(salesPerson.fName == this.fName &&
salesPerson.lName == this.fName &&
salesPerson.personAge == this.personAge);
}
The test for non-null is guaranteed to run first and therefore no potential NullReferenceException can occur in the rest of the equality test.

You code seems very overcomplicated. I'd replace it with this:
public override bool Equals(object obj)
{
SalesPerson temp = obj as SalesPerson;
if(temp == null) return false;
return temp.fName == this.fName && temp.lName == this.fName
&& temp.personAge == this.personAge;
}
You could then write some operators == != etc..

I recommend to use the reflector tool and learn best practices directly from Microsoft's code.
For example, System.Reflection.Module class equals function implementation:
public override bool Equals(object o)
{
if (o == null)
{
return false;
}
if (!(o is Module))
{
return false;
}
Module internalModule = o as Module;
internalModule = internalModule.InternalModule;
return (this.InternalModule == internalModule);
}
EDIT: Changed the implementation example to Module class.

I find Resharper a very useful tool for 'drudge' work such as this, and can certainly help you focus on what you are trying to achieve over the implementation detail.
See here for more info. If there are alternatives I'm open to hear them.

Related

Compare 2 class objects and ignore 1 (or more) property?

So I created a class like this:
public class ClassName
{
public int ID;
public String n_1 {get; set; }
public String n_2 {get; set; }
// ....
public String n_x {get; set; }
}
Later in my code I compare 2 ClassName objects:
ClassName Item_1 /*...*/ ;
ClassName Item_2 /*...*/ ;
Like this:
if (Item_1 != Item_2 && Item_1.n_a == Item_2.n_a)
{
//do something
}
Now my Problem is that Item_1.ID and Item_2.ID should be ignored. Is there a easy way to do this? The only solution I came up with is a no brainer of like
if ( (Item_1.n_1 != Item_2.n_1 || Item_1.n_2 != Item_2.n_2 || /* ... */ ) && Item_1.n_a == Item_2.n_a)
Override the object.Equals method in your class and specify how you want it to be compared.
Then use !Item1.Equals(Item2) instead of !=
https://learn.microsoft.com/en-us/dotnet/api/system.object.equals?view=netframework-4.7.2
The easy way is what you are actually doing , just create a method like this
public bool Method(ClassName Item_1,ClassName Item2)
{
bool check=false;
if ( (Item_1.n_1 != Item_2.n_1 || Item_1.n_2 != Item_2.n_2 || /* ... */ ) && Item_1.n_a == Item_2.n_a)
check=true
return check
}
To perform something like Item_1 != Item_2 or Item_1 == Item_2 and get all properties (or the ones you want) to be compared, you need to implement your own Equals method and ==, != operators overloads.
== operator, from MSDN:
For reference types other than string, == returns true if its two operands refer to the same object.
For that you can start with some straightforward solution, to implement IEquatable<T> interface, fill your comparing logic inside Equals method and overload == and != operators internally calling your type-safe Equals method:
public class ClassName : IEquatable<ClassName>
{
public int ID;
public String n_1 { get; set; }
public String n_2 { get; set; }
// ....
public String n_x { get; set; }
public static bool operator ==(ClassName obj1, ClassName obj2)
{
if (((object)obj1) == null || ((object)obj2) == null)
return Equals(obj1, obj2);
return obj1.Equals(obj2);
}
public static bool operator != (ClassName obj1, ClassName obj2)
{
if (((object)obj1) == null || ((object)obj2) == null)
return !Equals(obj1, obj2);
return !obj1.Equals(obj2);
}
public bool Equals(ClassName obj)
{
if (obj == null) return false;
return (n_1 == obj.n_1) && (n_2 == obj.n_2) && (n_x == obj.n_x); //you can ignore ID here
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
ClassName classNameObj = obj as ClassName;
if (classNameObj == null)
return false;
else
return Equals(classNameObj);
}
public override int GetHashCode()
{
//This code was generated by VS ide, you can write your own hashing logic
var hashCode = 1032198799;
hashCode = hashCode * -1521134295 + ID.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(n_1);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(n_2);
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(n_x);
return hashCode;
}
}
Then you can check in your if:
if (Item_1 != Item_2)
{
//Do Something
}
For Equals method you should stick to Guidelines for Overriding Equals() and Operator == .
References: == Operator, != Operator, IEquatable Interface, IEquatable.Equals(T) Method, Guidelines for Overriding Equals() and Operator ==

Error while fetching data from sorted dictionary in C#

I have a SortedDictionary<Package, List<string>>. Following is the Package class:
using System;
namespace GetPackageInfo
{
public class Package : IComparable, IEquatable<Package>
{
public string PackageName;
public string Version;
public Package()
{
}
public Package(string packageName)
{
this.PackageName = packageName;
}
public override int GetHashCode()
{
unchecked
{
int result = 17;
result = result * 23 + ((PackageName != null) ? this.PackageName.GetHashCode() : 0);
result = result * 23 + ((Version != null) ? this.Version.GetHashCode() : 0);
return result;
}
}
public bool Equals(Package other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Equals(this.PackageName, other.PackageName) &&
Equals(this.Version, other.Version);
}
public override bool Equals(object obj)
{
Package temp = obj as Package;
if (temp == null)
return false;
return this.Equals(temp);
}
public override string ToString()
{
return string.Format("PackageName: {0}, Version: {1}", PackageName, Version);
}
public int CompareTo(object obj)
{
if (obj == null)
return 1;
if (obj != null)
return (Equals(obj) ? -1 : 1);
else
throw new ArgumentException("Object is not a Temperature");
}
Whenever I do a Contains or ContainsKey on the SortedDictionary, it does not work even when the name and version is the same.
if (nugetPackagesInfo.Keys.Any(p => p.Equals(package)))
{
//List<string> currPackage;
//nugetPackagesInfo.TryGetValue(package, out currPackage);
if (!nugetPackagesInfo[package].Contains(packageFile))
{
nugetPackagesInfo[package].Add(packageFile);
}
nuGetPackagesInfo is my dictionary object. The Any returns true though. But once it is passed and gets to nugetPackagesInfo[package], then it throws the KeyNotFoundException. Can you please help me figure it out? Is my CompareTo not correct?
Your implementation of CompareTo doesn't seem to be correct. In fact, you don't implement any ordering of packages. You should, most likely, order packages by name, and if equal by version.
The core of Package.CompareTo should look like this (simplified; not taking care of other == null):
// try name ordering
int nameOrdering = this.Name.CompareTo(other.Name);
// names not equal ⇒ ordering is clear and no need to inspect further
if (nameOrdering != 0)
{
return nameOrdering;
}
// names are equal ⇒ resort to version ordering
else
{
return this.Version.CompareTo(other.Version);
}
You should also read the documentation for String.CompareTo() because of its culture-specific semantics.
Change CompareTo and GetHashCode to these implementations.
public int CompareTo(object obj)
{
if (obj == null)
return 1;
return this.ToString().CompareTo(obj.ToString());
}
public override int GetHashCode()
{
unchecked
{
return ((PackageName != null ? PackageName.GetHashCode() : 0)*397) ^ (Version != null ? Version.GetHashCode() : 0);
}
}
public override string ToString()
{
return string.Format("PackageName: {0}, Version: {1}", PackageName??"", Version ?? "");
}
CompareTo - see the documentation. By using ToString() you get a comparison on the package name and then the version without having to do your own checks. Just make sure that ToString is correct (I added null check so it does not throw an Exception).
GetHashCode - not sure where you got your implementation from. You need to make sure that the hashcode is always unique for that item unless they truely are equal. This is the implementation I found on this previous answer on SO, see the last edit in the answer..
Your CompareTo method should work as this:
return -1 if this is smaller than obj
return 1 if this is bigger than obj and
most important: return 0 if this equals obj

Reproduce the infinite loop with overriden Equals

Recently I decided to play around with overriding the Equals method. I used mainly the MSDN guideline (the updated one I believe). So my implementation end up like this:
public class EqualityCheck
{
public int Age { get; set; }
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
public override bool Equals(object obj)
{
if (null == obj)
{
return false;
}
//If obj is on of the expected type return false
EqualityCheck ec = obj as EqualityCheck;
if (null == ec)
{
return false;
}
//return true if the fields match. This is the place where we can decide what combination should be unique
return (Age == ec.Age) && (Name == ec.Name) && (DateOfBirth == ec.DateOfBirth);
}
public bool Equals(EqualityCheck ec)
{
// If parameter is null return false:
if (ec == null)
{
return false;
}
// Return true if the fields match:
return (Age == ec.Age) && (Name == ec.Name);
}
//How to implement GetHashCode for complex object?
}
And also one child class:
public class EqualityCheckChild : EqualityCheck
{
public int Height { get; set; }
public override bool Equals(System.Object obj)
{
// If parameter cannot be cast to ThreeDPoint return false:
EqualityCheckChild ec1 = obj as EqualityCheckChild;
if (ec1 == null)
{
return false;
}
// Return true if the fields match:
return base.Equals(obj) && Height == ec1.Height;
}
public bool Equals(EqualityCheckChild ec1)
{
// Return true if the fields match:
return base.Equals((EqualityCheck)ec1) && Height == ec1.Height;
}
public static bool operator ==(EqualityCheckChild a, EqualityCheckChild b)
{
if (Equals(a, b))
{
return true;
}
if (a == null || b == null)
{
return false;
}
return a.DateOfBirth == b.DateOfBirth && a.Name == b.Name;
}
public static bool operator !=(EqualityCheckChild a, EqualityCheckChild b)
{
return !(a == b);
}
}
I think this is what MSDN shows as implementation, just with removed casts.
I am using VS2015 and .NET 4.5.2. VS marked the casting as redundant, that's when I look up what's the issue with this. I've read about the possible infinity loop and just out of curiosity I decided to recreate it with the code above. However I can't reproduce it.
Since this is not copy-paste code. At least not literally. I wrote it by hand trying to understand what I am doing so I guess it's possible to have some mismatch with the original code which leads to this. But still my question remains - how to reproduce the problem which is also mentioned in the MSDN article?
Attempt to compare an instance of EqualityCheckChild to null.
EqualityCheckChild foo = new EqualityCheckChild();
Console.WriteLine(foo == null);
This code snippet will cause a StackOverflowException, because in the operator== method, if (a == null || b == null) calls itself.

GetHashCode Equality

I've wondered about this, so I figure I'll ask it.
Most places you'll see use the same semantic logic for overriding Equals as GetHashCode for memberwise equality...however they usually use different implementations:
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
var other = (MyType)obj;
if (other.Prop1 != Prop1)
{
return false;
}
return true;
}
public override int GetHashCode()
{
int hash = -657803396;
num ^= Prop1.GetHashCode();
return num;
}
If you're implementing memberwise equality for your type (lets say for storing in a dictionary), why not just override GetHashCode then do something like this for Equals:
public override bool Equals(object obj)
{
return this.HashEqualsAndIsSameType(obj);
}
public static bool HashEquals(this object source, object obj)
{
if (source != null && obj != null)
{
return source.GetHashCode() == obj.GetHashCode();
}
if (source != null || obj != null)
{
return false;
}
return true;
}
public static bool HashEqualsAndIsSameType<T>(this T source, object obj)
{
return (obj == null || obj.GetType() == typeof(T)) && source.HashEquals(obj);
}
Because there is a real risk of conflicts. Hash-codes are not unique. They can (when different) prove inequality, but never equality. When looking for an item:
get the hash-code(s)
if the hash-code is different, the object is different; discard it
if the hash-code is the same, check Equals:
if Equals reports true they are the same
else discard
Consider long... since hash-code is int, it is easy to see that there are lots and lots of conflicts.
Hashes are not 1-to-1, you can have multiple different values that hash to the same value, but which should compare as not equal. So you cannot really implement Equals in terms of GetHashCode. This is why you have collisions in a hash table, and why a hash table lookup must involve call(s) to both GetHashCode and Equals.

overload Equals, is this wrong?

Reading some piece of code and I keep seeing this :
public override bool Equals (object obj)
{
if (obj == null || this.GetType ().Equals (obj.GetType())) return false;
//compare code...
}
Shouldn't it be like this (note the !):
public override bool Equals (object obj)
{
if (obj == null || !this.GetType ().Equals (obj.GetType())) return false;
//compare code...
}
Or does the equals perform differently in this case?
That looks like a bug. Returning false when the types are the same is certainly not the intended behaviour.

Categories