Reputation: 5148
I have the following classes:
public class MyDocuments
{
public DateTime registeredDate;
public string version;
public List<Document> registeredDocuments;
}
public class Document
{
public string name;
public List<File> registeredFiles;
}
public class File
{
public string name;
public string content;
}
I have an instance of MyDocuments which has several documents in List<Document> registeredDocument
. I get a new List<Document>
from the user.
How can I verify that the new object doesn't exist in the list? I want to compare by value not reference.
I'm thinking of using HashSet instead of List. Is this the proper approach?
Upvotes: 2
Views: 563
Reputation:
Something like this at the top level, continued down at the sub-levels:
public class MyDocuments
{
public DateTime registeredDate;
public string version;
public HashSet<Document> registeredDocuments;
public override bool Equals(Object o)
{
if( !(o is MyDocuments) ) return false;
MyDocuments that = (MyDocuments)o;
if( !String.Equals(this.version, that.version) ) return false;
if( this.registeredDocuments.Count != that.registeredDocuments.Count ) return false;
// assuming registeredDate doesn't matter for equality...
foreach( Document d in this.registeredDocuments )
if( !that.registeredDocuments.Contains(d) )
return false;
return true;
}
public override int GetHashCode()
{
int ret = version.GetHashCode();
foreach (Document d in this.registeredDocuments)
ret ^= d.GetHashCode(); // xor isn't great, but better than nothing.
return ret;
}
}
Note: Caching could be useful for the HashCode values if the properties were change-aware.
Upvotes: 0
Reputation: 437604
Whenever the BCL classes want to perform an equality check between objects of some type T
, they do so by calling one or both of the methods in some implementation of IEqualityComparer<T>
. To get hold of such an implementation, the framework looks to EqualityComparer<T>.Default
.
As mentioned in the documentation, this property produces an IEqualityComparer<T>
like this:
The
Default property
checks whether type T implements theSystem.IEquatable<T>
interface and, if so, returns anEqualityComparer<T>
that uses that implementation. Otherwise, it returns anEqualityComparer<T>
that uses the overrides ofObject.Equals
andObject.GetHashCode
provided byT
.
So, in general, to dictate how equality comparisons should be performed you can:
IEqualityComparer<T>
to the class or method that performs equality checks. This option is not very visible with List<T>
, but many LINQ methods (such as Contains
) do support it.IEquatable<T>
. This will make EqualityComparer<T>.Default
use this implementation, and is a good choice whenever there is an obvious "natural" way to compare objects of type T
.object.GetHashCode
and object.Equals
without implementing IEqualityComparer<T>
. However, this is simply an inferior version of #2 and AFAIK should always be avoided.A good rule of thumb is: if there is an obvious and natural way to compare objects of class T
, consider having it implement IEquatable<T>
; this will make sure your comparison logic is used throughout the framework without any additional involvement. If there is no obvious candidate, or if you want to compare in a manner different than the default, implement your own IEqualityComparer<T>
and pass the implementation as an argument to the class or method that needs to perform equality checks.
Upvotes: 2
Reputation: 22955
You should implement IEquatable<T>
.
When you implement this interface on your custom object, any equality checks (e.g. Contains, IndexOf) are automatically done using your objects implementation.
Upvotes: 1
Reputation: 13706
You will need to implement the Equals()
method, and probably GetHashCode()
as well. See this answer for an example.
Upvotes: 1
Reputation: 31204
override the object.Equals method.
here's an example straight from the documentation
public class Person
{
private string idNumber;
private string personName;
public Person(string name, string id)
{
this.personName = name;
this.idNumber = id;
}
public override bool Equals(Object obj)
{
Person personObj = obj as Person;
if (personObj == null)
return false;
else
return idNumber.Equals(personObj.idNumber);
}
public override int GetHashCode()
{
return this.idNumber.GetHashCode();
}
}
the Equals
method returns a bool which is whether or not obj
is equal to this
Upvotes: 0