3

I would like to compare two classes that look like this

public class Order
{
        public string KundNummer, KundNamn, ErReferens, VarReferens, KontraktsNummer, Betvillk, Levvillk, Levsatt, Speditor,
            Resenh, Projekt, OrderDatum, LeveransDatum, ErtOrdernr, LagerbokfDatum, KundPostAdr, KundPostAdr2, KundGLN, KundPostnr, 
            KundOrt, KundLandKod, KundLand, KundVATnr, KundDistrikt, KundSaljare, KundText1, KundText2, KundText3, KundSprak,
            KundValuta, KundRabattAvtal, KundRabattAvtalBenamning, KundPrislista, KundPrislistaBenamning, KundALnamn, KundALpostAdr, KundALpostAdr2, KundALGLN, KundALpostnr, KundALort,
            KundALlandKod, KundALland;
        public double OrderNummer, Fakturarabatt, Frakt, Expavg, Brutto, Netto, ExklMoms, Totalt, Moms, Avrundn, KundValutaKurs, KundValutaEnhet;
        public int EUPeriodSamman, InklMoms, EjKlar, Levererad, Malukerad, BestallningSkapad, Ordererk,
            Plocklista, Foljesedel, ExtraOrderdokument, Restorder, Faktura, KundSparaText, KundExport, KundRantefakturering, KundKravbrev,
            KundKravavgift, KundRestnoteraEj, KundSamlingsfakturera;
    }

i want to compare two objects of this class for logging which fields in my database that changed.

public string OrderUppdateraOrder(Order order)
    {
        Order OrderToCompare = new Order();
        OrderToCompare = OrderVisaOrderInformation(order.OrderNummer);

        //then the code goes on to make the changes to the database from the class order
        //while OrdertoComapre still have the values from before this function was called
    }

So is it possible to loop through these classes and compare them or do I have to write an if for every variable in my class? :)

Or maybe convert it to a List? I don't know? :P

Thank you for answers

17
  • 1
    This might help you: stackoverflow.com/questions/6240385/… However, that's bad practice. Commented Nov 21, 2012 at 9:46
  • 1
    I HAVE to mention this: Please use better variable names, for your own sake and the sake of your colleagues. Using abbreviations in variable names is most of the time a really bad habit. When you look at your code in months again, can you remember what all your abbreviations mean? Just use better variable names, it comes with no penalty except of having to write a bit more (which is hardly an argument with a good editor). Commented Nov 21, 2012 at 9:51
  • 2
    user1793714: i named them like the fields are named in the swedish version of: visma administration 2000. Commented Nov 21, 2012 at 9:53
  • 1
    Now that you've clarified the purpose, perhaps you could adapt this to allow for fields Commented Nov 21, 2012 at 9:59
  • 1
    @Dendei, Just a side-note: Not that it matters but is this homework? If not, you might want to store "Kund" (Customer in Swedish) as a reference on the Order instead of storing all the fields on it. Commented Nov 21, 2012 at 10:06

3 Answers 3

3

i want to log if there is a difference and log the difference something like this CustomerNumber: changed from 456 to 345

The best option is probably just to use reflection to crawl over the public properties and fields, comparing them. This will have less code to compare, but will have a performance overhead. You can greatly reduce that overhead using tools like FastMember:

static class Program {
    static void Main()
    {
        Order o1 = new Order { Resenh = "abc" },
              o2 = new Order { Resenh = "abc" };
        ShowDiffs(o1, o2); // {nothing}
        o2.Resenh = "def";
        ShowDiffs(o1, o2); // Resenh changed from abc to def
    }
    static void ShowDiffs<T>(T x, T y)
    {
        var accessor = TypeAccessor.Create(typeof(T));
        if (!accessor.GetMembersSupported) throw new NotSupportedException();
        var members = accessor.GetMembers();

        foreach (var member in members)
        {
            object xVal = accessor[x, member.Name],
                   yVal = accessor[y, member.Name];
            if (!Equals(xVal, yVal))
            {
                Console.WriteLine("{0} changed from {1} to {2}",
                    member.Name, xVal, yVal);
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

@LukeHennerley Yes... it would. The generic type can be inferred from the arguments supplied to the method call.
this looks like exactly what i want but im just checking up on things i dont understand so well. so bear with me i you are waiting for solved mark ^^
is TypeAccessor from FastMember? cant find much on it? i'll test it :)
@Dendei yes, that is from FastMember - basically, it is a small utility library I wrote that wraps up the most common reflection operations, and bundles in some meta-programming for performance
@Dendei you could do exactly the same thing with typeof(T).GetFields(...), and someField.GetValue(obj) - it would just be much slower
1

Ok from how I understand you - you have a method which will retreive an Order object from the database and an Order object which you may have intially got from a database, but modified. You want to check if one, or many orders have change without saying:

For each order if Database.A equals Your.A etc.

I would put your check into one place and override the Equals method.

  public class Order
  {
    public int Id;
    public string SomeProp;
    public string AnotherProp;
    public override bool Equals(object obj)
    {
      Order orderToCompare = (Order)obj;
      return (SomeProp == orderToCompare.SomeProp && AnotherProp == orderToCompare.AnotherProp);
    }
  }

Then have two methods, one for updating a single order and one for updating many orders.

private void UpdateOrder(Order o)
{
  //Get the corresponding order from the database (I suspect Entity Framework here in order to get an object?)
  Order dbOrder = OrderVisaOrderInformation(o.Id);
  if (dbOrder.Equals(o))
  {
    //Do some update
  }
}
private void UpdateManyOrders(List<Order> orders)
{
  var dbOrders = (from order in orders
                  select OrderVisaOrderInformation(order.Id));
  List<Order> ordersToUpdate = dbOrders.Where(x => !x.Equals(orders.First(y => y.Id == x.Id))).ToList();
  foreach (Order orderToUpdate in ordersToUpdate)
  {
    //Update the order
  }
}

This may be wrong but from how I understand your question, this is what you want to do.

4 Comments

If you see the comments, the requirement is a memberwise breakdown of changes. Also: if you override Equals you should also override GetHashCode - and for this many members that is high-maintenance
@MarcGravell I see... I started doing this answer whilst the many comments were happening. Thanks.
I can relate... I have a deleted answer doing an optimized Expression comparison ;p
sorry for if im slow at answering im just checking through all the posts :) but im not sure, the order object in public string OrderUppdateraOrder(Order order) function is what the user writes in to change in the database. And before the changes take place i make an same object with the values before the changes take place so i can compare and log the differences. so one object has the values the database have right now and one have the values that will overwrite the current ones in the database. hope this makes sense
1

Maybe this approach can help you

public class Order
{
    public string KundNummer, KundNamn, ErReferens, VarReferens, KontraktsNummer, Betvillk, Levvillk, Levsatt, Speditor,
        Resenh, Projekt, OrderDatum, LeveransDatum, ErtOrdernr, LagerbokfDatum, KundPostAdr, KundPostAdr2, KundGLN, KundPostnr,
        KundOrt, KundLandKod, KundLand, KundVATnr, KundDistrikt, KundSaljare, KundText1, KundText2, KundText3, KundSprak,
        KundValuta, KundRabattAvtal, KundRabattAvtalBenamning, KundPrislista, KundPrislistaBenamning, KundALnamn, KundALpostAdr, KundALpostAdr2, KundALGLN, KundALpostnr, KundALort,
        KundALlandKod, KundALland;
    public double OrderNummer, Fakturarabatt, Frakt, Expavg, Brutto, Netto, ExklMoms, Totalt, Moms, Avrundn, KundValutaKurs, KundValutaEnhet;
    public int EUPeriodSamman, InklMoms, EjKlar, Levererad, Malukerad, BestallningSkapad, Ordererk,
        Plocklista, Foljesedel, ExtraOrderdokument, Restorder, Faktura, KundSparaText, KundExport, KundRantefakturering, KundKravbrev,
        KundKravavgift, KundRestnoteraEj, KundSamlingsfakturera;

    public static bool operator ==(Order left, Order right)
    {
        foreach (var field in left.GetType().GetFields())
        {
            object valueLeft = field.GetValue(left);
            object valueRight = field.GetValue(right);

            if (!object.Equals(valueLeft, valueRight))
                return false;
        }

        return true;
    }

    public static bool operator !=(Order left, Order right)
    {
        return !(left == right);
    }

}

1 Comment

object.Equals(valueLeft,valueRight) would be more appropriate than using a comparer and checking for 0; also, if you see the comments, the intent is a memberwise breakdown of changes

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.