i need to compare two objects but compare a number of their properties in one hit. this is not for sorting, but instead to confirm whether anything has changed; as one is the old saved instance, and th开发者_StackOverflow中文版e second is a newly imported instance of the same thing
i assume this is best served by writing a custom comparer. just am a bit confused as to whether to do IComparer
, or IComparable
, or what tbh.
thanks
nat
If you only have a single definition of equality for your class, you don't really need to implement any interface: simply override the Equals
method. Best practice though, would be to implement IEquatable<T>
and to override GetHashCode
sensibly (if you don't override the hash-code, equality will misbehave when collection classes, LINQ methods etc. use it as a pre-condition for equality). Here's a sample implementation:
public class Person : IEquatable<Person>
{
public string Name { get; set; }
public int Age { get; set; }
public override int GetHashCode()
{
return (Name == null ? 0 : Name.GetHashCode()) ^ Age;
}
public override bool Equals(object obj)
{
return Equals(obj as Person);
}
public bool Equals(Person other)
{
return other != null && other.Name == Name && other.Age == Age;
}
}
This will allow you to do:
Person savedPerson = ...
Person importedPerson = ...
bool hasChanged = !savedPerson.Equals(importedPerson);
If, on the other hand, you do have lots of different definitions of equality for different circumstances, your best bet would be to write up different IEqualityComparer<T>
implementations. Here's a sample implementation:
public class AgeComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
return (x == null || y == null) ? x == y : x.Age == y.Age;
}
public int GetHashCode(Person obj)
{
return obj == null ? 0 : obj.Age;
}
}
In this case, the check will look like:
Person savedPerson = ...
Person importedPerson = ...
IEqualityComparer<Person> comparer = ...
bool hasChanged = !comparer.Equals(savedPerson, importedPerson);
As you have alluded to IComparable is typically used for sorting.
In this case you would want to overload the comparison operator: ==
Because the reverse comparison should also be valid, this implies you must also overload the != operator.
When you overload == and !- you are also expected to override Equals and GetHashCode.
A decent C# book should explain the details.
An alternative to implementing the IComparable interface would be to override the Equals and GetHashCode functions.
That is about how you want to perform compare operation. You can do the operation in both ways:
public void Method()
{
Foo p1 = new Foo();
Foo p2 = new Foo();
p1.CompareTo(p2);
FooComparer c = new FooComparer();
c.Compare(p1, p2);
}
class Foo : IComparable
{
public int CompareTo(object obj)
{
throw new NotImplementedException();
}
}
class FooComparer : IComparer<Foo>
{
public int Compare(Foo x, Foo y)
{
throw new NotImplementedException();
}
}
I prefer using IComparer as seperation of concerns. Foo is my class, I have some busines needs on it. If I want to compare some Foos, I use FooComparer. For your situation you can return the number of changed properties from Compare method. If Compare method return 0. Then two Foos are same.
As I said. That is completely how you want to perform the action I think. Overriding Equality Operators are also good solution. Implementing IEqualityComparer<T>
is another solution.
Yes you will need your type to implement IComparable. Here is a sample on how to do it.
精彩评论