Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# compare the data in two object models

I have a dialog, when spawned it gets populated with the data in an object model. At this point the data is copied and stored in a "backup" object model. When the user has finished making their changes, and click "ok" to dismiss the dialog, I need a quick way of comparing the backup object model with the live one - if anything is changed I can create the user a new undo state.

I don't want to have to go and write comparison function for every single class in the object model if possible.

If I serialised both object models and they were identical but stored in different memory locations would they be equal? Does some simple way exist to compare two serialised object models?

like image 379
DrLazer Avatar asked Jan 06 '11 15:01

DrLazer


2 Answers

I didn't bother with a hash string but just a straight Binary serialisation works wonders. When the dialog opens serialise the object model.

BinaryFormatter formatter = new BinaryFormatter();
m_backupStream = new MemoryStream();
formatter.Serialize(m_backupStream,m_objectModel);

Then if the user adds to the object model using available controls (or not). When the dialog closes you can compare to the original serialisation with a new one - this for me is how i decide whether or not an Undo state is required.

BinaryFormatter formatter = new BinaryFormatter();
MemoryStream liveStream = new MemoryStream();
formatter.Serialize(liveStream,m_objectModel);
byte[] streamOneBytes = liveStream.ToArray();
byte[] streamTwoBytes = m_backupStream.ToArray();
if(!CompareArrays(streamOneBytes, streamTwoBytes))
    AddUndoState();

And the compare arrays function incase anybody needs it - prob not the best way of comparing two arrays im sure.

private bool CompareArrays(byte[] a, byte[] b)
{
    if (a.Length != b.Length)
       return false;

    for (int i = 0; i < a.Length;i++)
    {
       if (a[i] != b[i])
        return false;
    }
    return true;
}
like image 169
DrLazer Avatar answered Sep 22 '22 09:09

DrLazer


I'd say the best way is to implement the equality operators on all classes in your model (which is usually a good idea anyway if you're going to do comparisons).

class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
    public ICollection<Chapter> Chapters { get; set; }

    public bool Equals(Book other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return Equals(other.Title, Title) && Equals(other.Author, Author) && Equals(other.Chapters, Chapters);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != typeof (Book)) return false;
        return Equals((Book) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int result = (Title != null ? Title.GetHashCode() : 0);
            result = (result*397) ^ (Author != null ? Author.GetHashCode() : 0);
            result = (result*397) ^ (Chapters != null ? Chapters.GetHashCode() : 0);
            return result;
        }
    }
}

This snippet is auto-generated by ReSharper, but you can use this as a basis. Basically you will have to extend the non overriden Equals method with your custom comparison logic.

For instance, you might want to use SequenceEquals from the Linq extensions to check if the chapters collection is equal in sequence.

Comparing two books will now be as simple as saying:

Book book1 = new Book();
Book book2 = new Book();

book1.Title = "A book!";
book2.Title = "A book!";

bool equality = book1.Equals(book2); // returns true

book2.Title = "A different Title";
equality = book1.Equals(book2); // returns false

Keep in mind that there's another way of implementing equality: the System.IEquatable, which is used by various classes in the System.Collections namespace for determining equality.

I'd say check that out as well and you're well on your way!

like image 22
Erik van Brakel Avatar answered Sep 22 '22 09:09

Erik van Brakel