views:

96

answers:

5

hi there

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 the 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

A: 

Yes you will need your type to implement IComparable. Here is a sample on how to do it.

Vinay B R
Your link points back to this thread. That's an example of recursion, not IComparable ;)
Marc
lol @Marc. Great catch.
KP
Perhaps he meant to link: http://support.microsoft.com/kb/320727
KP
and i would return 0 for the same and either 1/-1 for not.. as this is not a sorting comparer.. it makes no odds to me.. ?!ie.public int CompareTo(object other){if(!this.stringprop.equals(other.stringprop))return -1;if(!this.stringprop2.equals(other.stringprop2)) return -1;and so on.. until// all is wellreturn 0;??
nat
sorry about that. have updated the link.
Vinay B R
+4  A: 

If you only have a single definition of equality for your class, you don't really need to implement any interface: simply override the Equalsmethod. 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);
Ani
How does the IEquatable Equals differ than the Equals defined on Object?
Greg
It adds a strongly-typed `Equals<T>` method. This prevents unnecessary casting under common circumstances.
Ani
looks like its the IEqualityComparer for me in this instance then, as i need to check a number of properties of my person.ie.managerID, phoneNumber, location.. etc and if any of them have changed i need the compare to return false.. unless i'm missing something?but maybe i am jsut misunderstanding what gethashcode does..
nat
@nat: Yes, exactly.
Ani
so like this?!myPersonComparer: IEqualityComparer<Person>{public bool Equals(Person x, Person y){if(x==null || y==null)return false;if(x.prop != y.prop) return false;if(x.prop2 != y.prop2) return false;//..etcreturn true;}}
nat
@nat: Yes, that sounds fine.
Ani
hi again Ani, just wondering how i should implement the gethashcode part of that. as there is nothing in the object that has an int associated with it.. the uniqueness of the object it defined by its id which is a guid.ok ignore this, I simply called getHashCode on the Guid Property of the object
nat
A: 

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.

Sisyphus
A: 

An alternative to implementing the IComparable interface would be to override the Equals and GetHashCode functions.

TheCee
A: 

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.

Musa Hafalır