Overriding equals in C# interface implementation - c#

I have a class that implements an interface, such as this:
interface IInterface
{
string PropA { get; }
string PropB { get; }
}
class AClass : IInterface
{
string PropA { get; protected set; }
string PropB { get; protected set; }
}
Equality is determined based on PropA and PropB. When overriding the Equals method for AClass, should I attempt to cast obj to AClass, like this:
public override bool Equals(object obj)
{
AClass other = obj as AClass;
return other != null
&& AClass.PropA == other.PropA
&& AClass.PropB == PropB;
}
Or should I attempt to cast obj to IInterface, like this:
public override bool Equals(object obj)
{
IInterface other = obj as IInterface;
return other != null
&& AClass.PropA == other.PropA
&& AClass.PropB == PropB;
}

You could do whichever you want. The two aren't the same, functionally, but which is "right" for you is something that we can't answer. If I have a BClass class that implements the same interface, and it has the same values for both properties, should it be equal to your AClass object? If yes, do the latter, if not, do the former.
Personally, I would find the latter concerning. Generally I find that if a class is going to implement its own personal definition of equality, other classes shouldn't be equal to it. One main reason is that it's preferable if equality is symetric. That is to say aclass.Equals(bclass) should return the same thing as bclass.Equals(aclass). Getting that behavior when you don't restrict equality to the same type is...hard. It requires cooperation of all related classes.
If you have some compelling reason to be comparing IInterface implementations in which they might be different underlying classes but still both be "equal", I'd personally prefer to create an IEqualityComparer<IInterface> that defines equality for that interface. This would the be separate from the definition of equality for either of the two implementing classes.

Decide how you need it to function.
Resharper implementation:
class AClass : IInterface, IEquatable<AClass>
{
public bool Equals(AClass other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(this.PropA, other.PropA) && string.Equals(this.PropB, other.PropB);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != typeof (AClass)) return false;
return Equals((AClass)obj);
}
public override int GetHashCode()
{
unchecked
{
return ((this.PropA != null ? this.PropA.GetHashCode() : 0) * 397) ^ (this.PropB != null ? this.PropB.GetHashCode() : 0);
}
}
public string PropA { get; protected set; }
public string PropB { get; protected set; }
}

If the purpose of the interface is to hide from consumers the fact that two equivalent objects might be of different classes, it may be a good idea to define a struct which holds a single private field of that interface type and chains to the appropriate methods of the interfaces. Use of such a struct should generally be essentially as efficient as using a variable of the interface type (the main exception would be if the struct ends up being boxed), but would shield client code from seeing the actual type of thing implementing the interface.
For example, one might have a interfaces IReadableMatrix<T> and IImmutableMatrix<T>, and corresponding structures ReadableMatrix<T> and ImmutableMatrix<T> with read-only members int Height, int Width, and T this[int row, int column], and ImmutableMatrix<T> AsImmutable();. Code which uses an ImmutableMatrix<double> shouldn't care how it's stored; it would be entirely possible that two instances of ImmutableMatrix might hold references to different implementations of IImmutableMatrix<T> which report identical content in every cell, but stored things entirely differently. One might be an instance of ArrayBackedMatrix<double>, which holds a 12x12 array that happens to hold zeroes in every element other than those on the diagonal, while the other might be a DiagonalMatrix<double>, and use a 12-item array that only stores things on the diagonal (and returns zero in response to a request for any other element). The use of different types to store the array data should be an implementation detail and not exposed to the client.
One slight detail of using a struct to wrap the arrays is that reference-type fields of a default-value structure will be null, but the structure itself will not. It may thus be desirable to either have the struct implement an IsNull property which returns true if the backing field is null, or else have the other struct members check whether the backing field is null and, if so, behave as an empty 0x0 matrix.

Related

Two objects being equal not regarded as distinct by LINQ

I'm comparing two objects of type Triangle and apparently they are deemed equal (I implemented my custom GetHaschCode as well as Equal method and operator).
List<Triangle> triangles = ...;
bool same = triangles[0] == triangles[1];
// same is true
However, when I go Distinct() on that list, it keeps all the elements (which sound to me like it's comparing by reference and not by my custom conditions). Is it so and what can I do about it?
int countBefore = triangles.Count();
int countAfter = triangles.Distinct().Count();
bool same = countBefore == countAfter;
// same is true, again
I'm missing something fairly obvious, am I not?
You can do this in one of two ways...
Either as Andrew says implement IEquatable
public class Triangle : IEquatable<Triangle>
{
bool IEquatable<Triangle>.Equals(Triangle other)
{
return Equals(other);
}
public override bool Equals(object obj)
{
//...
}
public override int GetHashCode()
{
//...
}
}
Or you could create another class that implements IEqualityComparer(T) and pass that into the Distinct method call.
public class TriangleComparer : IEqualityComparer<Triangle>
{
public bool Equals(Triangle x, Triangle y)
{
return x.Equals(y);
}
public int GetHashCode(Triangle obj)
{
return obj.GetHashCode();
}
}
You need to implement the IEquatable(T) interface in your Triangle class.
From the Enumerable.Distinct() documentation:
The default equality comparer, Default, is used to compare values of
the types that implement the IEquatable generic interface. To
compare a custom data type, you need to implement this interface and
provide your own GetHashCode and Equals methods for the type.

IComparable in C#

I have an object called Shape which contains a public int[,] coordinate { get; set; } field.
I have a separate class which has a collection of Shape objects. At a particular point, I wish to check:
if(shapes.Contains(shape))
{
// DoSomething
}
So in the Shape class I have added the IComparable reference and inserted the CompareTo method:
public int CompareTo(Shape other)
{
return this.coordinate.Equals(other.coordinate);
}
I am however getting an error:
Cannot implicitly convert type 'bool' to 'int'
How do I therefore phrase the return so that it returns an int and not a bool as it is doing so at the moment?
UPDATE
If I change the return code to:
return this.coordinate.CompareTo(other.coordinate);
I get the following error mesage:
Error 1 'ShapeD.Game_Objects.Shape' does not implement interface member 'System.IComparable.CompareTo(ShapeD.Game_Objects.Shape)'. 'ShapeD.Game_Objects.Shape.CompareTo(ShapeD.Game_Objects.Shape)' cannot implement 'System.IComparable.CompareTo(ShapeD.Game_Objects.Shape)' because it does not have the matching return type of 'int'. C:\Users\Usmaan\Documents\Visual Studio 2012\Projects\ShapeD\ShapeD\ShapeD\Game Objects\Shape.cs 10 18 ShapeD
IComparable implies, that two object can be compared in a sense, that you can tell which object has "higher value". It is generally used for sorting purposes. You should override Equals method instead .You should also use Point struct instead of array.
class Shape : IEquatable<Shape>
{
public Point coordinate { get; set; }
public bool Equals(Shape other)
{
if (other == null) return false;
return coordinate.Equals(other.coordinate);
}
public override bool Equals(object other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
var shape = other as Shape;
return Equals(shape);
}
public override int GetHashCode()
{
return coordinate.GetHashCode()
}
}
Since you only want to check for equality implement IEquatable interface not IComparable.
IComparable is used for sorting purpose
public bool Equals(Shape s)
{
int count=0;
int[] temp1=new int[this.coordinate.Length];
foreach(int x in this.coordinate)temp1[count++]=x;//convert to single dimention
count=0;
int[] temp2=new int[s.coordinate.Length];
foreach(int x in s.coordinate)temp2[count++]=x;//convert to single dimention
return temp1.SequenceEqual(temp2);//check if they are equal
}
NOTE
IEquatable should be implemented for any object that might be stored in a generic collection else you would have to also override Object's Equals method.Also as pointed out in other ans use Point struct instead of multidimentional array
For performing Contains check you need to override Equals operator in Shape class.
Resurrecting an old question only because it can still cause google hits despite some really poor answers.
You should not be using either CompareTo or Equals.
Neither of these fits with what you are trying to do and will only cause confusion, as evidenced by the answers written here.
Write your own method called something like IntersectsWith.
Have a look into any decent geometry library (e.g. boost if you're happy pulling from c++) as how to go about doing this.
As to casting from bool to int, this can be easily done by using the bool with the ? ternary operator.

ExceptWith in HashSet for complex types

I have HashSet of my custom class:
public class Vertex
{
public string Name;
public override bool Equals(object obj)
{
var vert = obj as Vertex;
if (vert !=null)
{
return Name.Equals(vert.Name, StringComparison.InvariantCulture);
}
return false;
}
}
And now I have tow hashsets
HashSet<Vertex> hashSet1 = new HashSet<Vertex>();
HashSet<Vertex> hashSet1 = new HashSet<Vertex>();
And now I'd like to have in hashSet1 only Vertexes that are not in hashSet2
So I use ExceptWith method
hashSet1.ExceptWith(hashSet2);
But this doesn't work.
I suppose that this doesn't work because I have complex type.
So the question is: is there some interface required to be implemented in Vertex class to make this thing work?
I know that while creation of HashSet I can pass a EqualityComparer but it seems to me that it would be more elegant to implement some comparing interface method in Vertex class.
Is it possible or I just doesn't understand sth?
Thanks.
When overriding Equals you should also override GetHashCode. HashSet (and other hashing structures like Dictionary) will first calculate a hash code for your objects to locate them in tne structure before comparing elements with Equals.
public override int GetHashCode()
{
return StringComparer.InvariantCulture.GetHashCode(this.Name);
}
You don't have to implement any interface (although IEquatable<T>) is encouraged. When you create a hash-set without specifying an equality-comparer, it defaults to using EqualityComparer<T>.Default, which asks the objects themselves to compare themselves to each other (special-casing null references).
However, in your case, your equality contract is broken since you haven't overriden GetHashCode. Here's how I would fix your type:
public class Vertex : IEquatable<Vertex>
{
public string Name { get; private set; }
public Vertex(string name)
{
Name = name;
}
public override int GetHashCode()
{
return StringComparer.InvariantCulture.GetHashCode(Name);
}
public override bool Equals(object obj)
{
return Equals(obj as Vertex);
}
public bool Equals(Vertex obj)
{
return obj != null && StringComparer.InvariantCulture.Equals(Name, obj.Name);
}
}
Would you mind overriding the .GetHashCode()too?
Here's the reference.
You have to override GetHashCode with Equals overriding.
Object.Equals Method:
Types that override Equals(Object) must also override GetHashCode; otherwise, hash tables might not work correctly.

c# List<T>.Contains() Method Returns False

In the code block below I would expect dictCars to contain:
{ Chevy:Camaro, Dodge:Charger }
But, dictCars comes back empty. Because this line returns false each time it's called:
if(myCars.Contains(new Car(Convert.ToInt64(strCar.Split(':')[1]),strCar.Split(':')[2])))
Code block:
public class Car
{
public long CarID { get; set; }
public string CarName { get; set; }
public Car(long CarID, string CarName)
{
this.CarID = CarID;
this.CarName = CarName;
}
}
List<Car> myCars = new List<Car>();
myCars.Add(new Car(0,"Pinto"));
myCars.Add(new Car(2,"Camaro"));
myCars.Add(new Car(3,"Charger"));
Dictionary<string, string> dictCars = new Dictionary<string, string>();
string strCars = "Ford:1:Mustang,Chevy:2:Camaro,Dodge:3:Charger";
String[] arrCars = strCars.Split(',');
foreach (string strCar in arrCars)
{
if(myCars.Contains(new Car(Convert.ToInt64(strCar.Split(':')[1]),strCar.Split(':')[2])))
{
if (!dictCars.ContainsKey(strCar.Split(':')[0]))
{
dictCars.Add(strCar.Split(':')[0], strCar.Split(':')[2]);
}
}
}
return dictCars;
Question: What am I doing wrong with my List.Contains implementation?
Thanks in advance!
You need to tell Contains what makes two Cars equal. By default it will use ReferenceEquals which will only call two objects equal if they are the same instance.
Either override Equals and GetHashCode in your Car class or define an IEqualityComparer<Car> class and pass that to Contains.
If two Cars that have the same CarID are "equal" then the implementation is pretty straightforward:
public override bool Equals(object o)
{
if(o.GetType() != typeof(Car))
return false;
return (this.CarID == ((Car)o).CarID);
}
public override int GetHashCode()
{
return CarID.GetHashCode();
}
Your Car class is a reference type. By default reference types are compared to each other by reference, meaning they are considered the same if they reference the same instance in memory. In your case you want them to be considered equal if they contain the same values.
To change the equality behavior, you need to override Equals and GetHashCode.
If two cars are equal only when ID and Name are equal, the following is one possible implementation of the equality members:
protected bool Equals(Car other)
{
return CarID == other.CarID && string.Equals(CarName, other.CarName);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
var other = obj as Car;
return other != null && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
return (CarID.GetHashCode() * 397) ^
(CarName != null ? CarName.GetHashCode() : 0);
}
}
This implementation has been created automatically by ReSharper.
It takes into account null values and the possibility of sub-classes of Car. Additionally, it provides a useful implementation of GetHashCode.
You can add this code, by implementing IEquatable
public class Car: IEquatable<Car>
{
......
public bool Equals( Car other )
{
return this.CarID == other.CarID && this.CarName == other.CarName;
}
}
Link : http://msdn.microsoft.com/fr-fr/library/vstudio/ms131187.aspx
You are assuming that two Car instances that have the same CarID and CarName are equal.
This is incorrect. By default, each new Car(...) is different from each other car, since they are references to different objects.
There are a few ways to "fix" that:
Use a struct instead of a class for your Car.
Structs inherit ValueType's default implementation of Equals, which compares all fields and properties to determine equality.
Note that in this case, it is recommended that you make your Car struct immutable to avoid common problems with mutable structs.
Override Equals and GetHashCode.
That way, List.Contains will know that you intend Cars with the same ID and Name to be equal.
Use another method instead of List.Contains.
For example, Enumerable.Any allows you to specify a predicate that can be matched:
bool exists = myCars.Any(car => car.ID == Convert.ToInt64(strCar.Split(':')[1])
&& car.Name = strCar.Split(':')[2]);
You need to implement Equals. Most probably as:
public override bool Equals(object obj)
{
Car car = obj as Car;
if(car == null) return false;
return car.CarID == this.CarID && car.CarName == this.CarName;
}
Your car class needs to implement interface IEquatable and define an Equals method, otherwise the contains method is comparing the underlying references.
You need to implement the IEqualityComparer
More information on how to do it can be found here;
http://msdn.microsoft.com/en-us/library/bb339118.aspx
// Custom comparer for the class
class CarComparer : IEqualityComparer<Car>
{
// Products are equal if their names and product numbers are equal.
public bool Equals(Car x, Car y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the properties are equal.
return x.CarID == y.CarID && x.CarName == y.CarName;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(Car car)
{
//Check whether the object is null
if (Object.ReferenceEquals(car, null)) return 0;
//Get hash code for the Name field if it is not null.
string hashCarName = car.CarName == null ? 0 : car.CarName.GetHashCode();
//Get hash code for the ID field.
int hashCarID = car.CarID.GetHashCode();
//Calculate the hash code for the product.
return hashCarName ^ hashCarID;
}
Check for equality;
CarComparer carComp = new CarComparer();
bool blnIsEqual = CarList1.Contains(CarList2, carComp);
A collection can never "contain" a newly newed object which uses the default Object.Equals comparison. (The default comparison is ReferenceEquals, which simply compares instances. This will never be true comparing an existing Car with a new Car())
To use Contains in this way, you will need to either:
Override Car.Equals (and Car.GetHashCode) to specify what it means to be equivalent, or
Implement an IEqualityComparer<Car> to compare the instances and specify that in your call to Contains.
Note the side effect that in the first option, other uses of Car.Equals(Car) will also use this comparison.
Otherwise, you can use Any and specify the comparison yourself (but IMHO this smells a little funny - a Car should know how to compare itself):
if(myCars.Any(c=> c.CarID == Convert.ToInt64(strCar.Split(':')[1]) && c.CarName == strCar.Split(':')[2]))
myCars.Contains(newCar)
myCars.Where(c => c.CarID == newCar.CarID && c.CarName==newCar.CarName).Count() > 0

Comparing two instances of a class

I have a class like this
public class TestData
{
public string Name {get;set;}
public string type {get;set;}
public List<string> Members = new List<string>();
public void AddMembers(string[] members)
{
Members.AddRange(members);
}
}
I want to know if it is possible to directly compare to instances of this class to eachother and find out they are exactly the same? what is the mechanism? I am looking gor something like if(testData1 == testData2) //Do Something And if not, how to do so?
You should implement the IEquatable<T> interface on your class, which will allow you to define your equality-logic.
Actually, you should override the Equals method as well.
public class TestData : IEquatable<TestData>
{
public string Name {get;set;}
public string type {get;set;}
public List<string> Members = new List<string>();
public void AddMembers(string[] members)
{
Members.AddRange(members);
}
// Overriding Equals member method, which will call the IEquatable implementation
// if appropriate.
public override bool Equals( Object obj )
{
var other = obj as TestData;
if( other == null ) return false;
return Equals (other);
}
public override int GetHashCode()
{
// Provide own implementation
}
// This is the method that must be implemented to conform to the
// IEquatable contract
public bool Equals( TestData other )
{
if( other == null )
{
return false;
}
if( ReferenceEquals (this, other) )
{
return true;
}
// You can also use a specific StringComparer instead of EqualityComparer<string>
// Check out the specific implementations (StringComparer.CurrentCulture, e.a.).
if( EqualityComparer<string>.Default.Compare (Name, other.Name) == false )
{
return false;
}
...
// To compare the members array, you could perhaps use the
// [SequenceEquals][2] method. But, be aware that [] {"a", "b"} will not
// be considerd equal as [] {"b", "a"}
return true;
}
}
One way of doing it is to implement IEquatable<T>
public class TestData : IEquatable<TestData>
{
public string Name {get;set;}
public string type {get;set;}
public List<string> Members = new List<string>();
public void AddMembers(string[] members)
{
Members.AddRange(members);
}
public bool Equals(TestData other)
{
if (this.Name != other.Name) return false;
if (this.type != other.type) return false;
// TODO: Compare Members and return false if not the same
return true;
}
}
if (testData1.Equals(testData2))
// classes are the same
You can also just override the Equals(object) method (from System.Object), if you do this you should also override GetHashCode see here
There are three ways objects of some reference type T can be compared to each other:
With the object.Equals method
With an implementation of IEquatable<T>.Equals (only for types that implement IEquatable<T>)
With the comparison operator ==
Furthermore, there are two possibilities for each of these cases:
The static type of the objects being compared is T (or some other base of T)
The static type of the objects being compared is object
The rules you absolutely need to know are:
The default for both Equals and operator== is to test for reference equality
Implementations of Equals will work correctly no matter what the static type of the objects being compared is
IEquatable<T>.Equals should always behave the same as object.Equals, but if the static type of the objects is T it will offer slightly better performance
So what does all of this mean in practice?
As a rule of thumb you should use Equals to check for equality (overriding object.Equals as necessary) and implement IEquatable<T> as well to provide slightly better performance. In this case object.Equals should be implemented in terms of IEquatable<T>.Equals.
For some specific types (such as System.String) it's also acceptable to use operator==, although you have to be careful not to make "polymorphic comparisons". The Equals methods, on the other hand, will work correctly even if you do make such comparisons.
You can see an example of polymorphic comparison and why it can be a problem here.
Finally, never forget that if you override object.Equals you must also override object.GetHashCode accordingly.
I see many good answers here but just in case you want the comparison to work like
if(testData1 == testData2) // DoSomething
instead of using Equals function you can override == and != operators:
public static bool operator == (TestData left, TestData right)
{
bool comparison = true; //Make the desired comparison
return comparison;
}
public static bool operator != (TestData left, TestData right)
{
return !(left == right);
}
You can override the equals method and inside it manually compare the objects
Also take a look at Guidelines for Overloading Equals() and Operator ==
You will need to define the rules that make object A equal to object B and then override the Equals operator for this type.
http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx
First of all equality is difficult to define and only you can define as to what equality means for you
Does it means members have same value
Or they are pointing to same location.
Here is a discussion and an answer here
What is "Best Practice" For Comparing Two Instances of a Reference Type?
Implement the IEquatable<T> interface. This defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances. More information here:
http://msdn.microsoft.com/en-us/library/ms131187.aspx

Categories

Resources