0

I have a 'Invoice' WinForm C# where it contains the usual textboxes and an unbound datagridview. I used a 'Invoice' class object to store the form fields' values. The datagridview rows are stored to a List < SubInvoice> properties in the 'Invoice'.

public static bool CompareObjects(object original, object altered)
{
    Type o = original.GetType();
    Type a = altered.GetType();

    foreach (PropertyInfo p in o.GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        Console.WriteLine("Original: {0} = {1}", p.Name, p.GetValue(original, null));
        Console.WriteLine("Altered: {0} = {1}", p.Name, p.GetValue(altered, null));

        if (p.GetValue(original, null).ToString() != p.GetValue(altered, null).ToString())
        {
            //Console.WriteLine("Not Equal");
            return false;
        }
    }

    return true;
}

I am using a global class with a method that uses Reflection to loop through the original 'invoice' object and compared it with the altered 'invoice'. If there is any difference, the user will be notified to save the invoice.

The above method works fine with all the properties of 'Invoice' class but I do not know how to check for the List in which it stores the value of each datagridrow into a 'SubInvoice' class object that stored it as an object in the list.

Can someone please give me some help here? I have also checked for similar thread in stackoverflow and other forums but in vain.

Update: I need to create a global generic method that will check for all type of classes. It can be 'Invoice', 'Customer'. The purpose is to track any changes made to the form at any particular instance and prompt the user to save.

5
  • This code will throw an Exception if o and a are different types, unless a happens to have all the same properties that o has. It will also not work as you intend if any of the properties are classes or structs, unless they happen to have overloaded ToString() to return a value that can be used as an equality comparison. Finally it will fail to detect a possible difference if a has properties that o does not have. Commented Oct 20, 2014 at 3:22
  • Yes of course. o and a are both the same invoice objects. The only differences are the values they hold. For example, o (as in original) may have $300.25 as the total value (double totalAmount property) and a (as in altered) may have $525.16 as the total value in the same property field. The 'Invoice' class has double, int, datetime properties and one List < subinvoice> property that contains a list of 'SubInvoice' class objects that represent each of the rows of datagridview values. Commented Oct 20, 2014 at 3:36
  • have you check cyotek.com/blog/… Commented Oct 20, 2014 at 3:37
  • Nothing in your code enforces that they are the same type. You could add a line requiring o and a to be the same type (still does not solve the issue of non-primitive properties in that generalized code. Commented Oct 20, 2014 at 3:39
  • @Damith I am checking now. Update: Yah I saw that before. As for Eric, will the object.Equals method checks for equality if it contains a list that contains 1 other class? Commented Oct 20, 2014 at 3:40

3 Answers 3

1

thank you all for your help.

I have stumbled into the following article while still eager to create a global generic method through reflection.

http://www.c-sharpcorner.com/UploadFile/1a81c5/custom-extension-method-to-compare-list-in-C-Sharp/

Here's the code if anyone is interested.

public static bool CompareObjects(object original, object altered)
{
    bool result = true;

    //Get the class
    Type o = original.GetType();
    Type a = altered.GetType();

    //Cycle through the properties.
    foreach (PropertyInfo p in o.GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        Console.WriteLine("Original: {0} = {1}", p.Name, p.GetValue(original, null));
        Console.WriteLine("Altered: {0} = {1}", p.Name, p.GetValue(altered, null));

        if (!p.PropertyType.IsGenericType)
        {
            if (p.GetValue(original, null) != null && p.GetValue(altered, null) != null)
            {
                if (!p.GetValue(original, null).ToString().Equals(p.GetValue(altered, null).ToString()))
                {
                    result = false;
                    break;
                }
            }
            else
            {
                //If one is null, the other is not
                if ((p.GetValue(original, null) == null && p.GetValue(altered, null) != null) || (p.GetValue(original, null) != null && p.GetValue(altered, null) == null))
                {
                    result = false;
                    break;
                }
            }
        }
    }

    return result;
}

public static bool CompareLists<T>(this List<T> original, List<T> altered)
{
    bool result = true;

    if (original.Count != altered.Count)
    {
        return false;
    }
    else
    {
        if (original != null && altered != null)
        {
            foreach (T item in original)
            {
                T object1 = item;
                T object2 = altered.ElementAt(original.IndexOf(item));

                Type objectType = typeof(T);

                if ((object1 == null && object2 != null) || (object1 != null && object2 == null))
                {
                    result = false;
                    break;
                }

                if (!CompareObjects(object1, object2))
                {
                    result = false;
                    break;
                }
            }
        }
        else
        {
            if ((original == null && altered != null) || (original != null && altered == null))
            {
                return false;
            }
        }
    }

    return result;
}

Usage: if (!xx.CompareObjects(searchedInvoice, alteredInvoice) | !xx.CompareLists(searchedInvoice.SubInvoice, alteredInvoice.SubInvoice))

Sign up to request clarification or add additional context in comments.

Comments

0

If you only whant to inform the user to save the pending changes then you should implement INotifyPropertyChanged instead of doing some black magic.

5 Comments

black magic, haha. Will this work with unbound datatable datagridview? Update: I have seen that example before too. My concern is the list object of 'Invoice' class contains another class.
Then implement the interface in that class (too). In you question you are saying that you have the original object and the altered one so you are modifing somehow the objects no matter the grid is bounded or not.
One more thing: comparing two list of objects; how can you tell on which indexes are the "same" objects, which ones are brand new, which of them is deleted? With INotifyPropertyChanged implemented you can use ObservableCollection<T> to monitor collection changes.
Yes it makes sense. I cannot possibly know the object in the list. Alright I will check out ObservableCollection<T>. It is new to me.
Come to think of it. I don't need to know which object in the list is changed. As long as there is any changes, be it removed, brand new or not, I will prompt the user for change. And I have checked out the INotifyPropertyChanged, I need to implement it in all the classes. Can you provide an example of reflection for objects in list so that I can have just one method to achieve the same result?
0

One trick I've seen before is to mark the objects as serializable, then serialize them in to strings and compare the strings. It may not be the most efficient method, but it is quick, easy, and works for almost any kind of data class. It even works for "complex" nested classes that have references to other classes.

One down-side is that it won't easily tell you what specifically changed, just that something is different.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.