开发者

Compare base class part of sub class instance to another base class instance

I have number of DTO classes in a system. They are organized in an inher开发者_如何学Pythonitance hierarchy.

class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string ListName { get; set; }
}

class PersonDetailed : Person
{
    public string WorkPhone { get; set; }
    public string HomePhone { get; set; }
    public byte[] Image { get; set; }
}

The reason for splitting it up is to be able to get a list of people for e.g. search results, without having to drag the heavy image and phone numbers along. Then the full PersonDetail DTO is loaded when the details for one person is selected.

The problem I have run into is comparing these when writing unit tests. Assume I have

Person p1 = myService.GetAPerson();
PersonDetailed p2 = myService.GetAPersonDetailed();

// How do I compare the base class part of p2 to p1?
Assert.AreEqual(p1, p2);

The Assert above will fail, as p1 and p2 are different classes. Is it possible to somehow only compare the base class part of p2 to p1? Should I implement IEquatable<> on Person? Other suggestions?


I believe that Assert.AreEqual calls the Equals method on the instances involved. You should be able to simply override the Equals logic and check to see at runtime whether you are comparing one of the possible cases:

  • Person <-> Person
  • Person <-> PersonDetailed
  • PersonDetailed <-> Person or
  • PersonDetailed <-> PersonDetailed

You can them implement the appropriate logic for each case, or delegate to an external comparer as you see fit. I don't know off-hand if any unit testing frameworks other than Microsofts support checking for IEquatable<T> when you ask them to verify equality.


A bit more investigation (based on LBushkin's answer) made me change my mind.

Assert.Equals calls the Equals method to compare the object. In my case I could have created an override on Person that would accept any type that can be casted to a Person and then compares all the attributes. This would make my original code work:

Assert.AreEqual(p1, p2);

I would also have to override Equals in my PersonExtended class to check the extra fields present. However that would have "funny" consequences:

Assert.AreEqual(p1, p2); // calls p1.Equals(p2) - evaluates to true.
Assert.AreEqual(p2, p1); // calls p2.Equals(p1) - evaluates to false.

At this point I decided to build something more simple - the result was an extension method on the Person type that compares. This has some advantages:

  • Can handle a null left-hand argument.
  • It is non-virtual - it is clear that the declared type of the variable is the comparison used.

Now all appeared to be well and I could continue coding. Until I found out that the entire idea of having inheritance between the basic and extended DTOs is flawed. I thought that the DataContractSerializer that WCF uses would serialize the type that the parameter of the function was declared as. It doesn't. It serializes the object's actual type. That means that if a PersonExtended object is passed to a method that only requires a Person the entire extended method is transferred over the wire anyways, so it's better to stick with simple composition.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜