Search code examples
c#reflectionobject-comparison

Reflection - object comparison & default values


I'm trying to compare two complex objects in C#, and produce a Dictionary containing the differences between the two.

If I have a class like so:

public class Product
{
    public int Id {get; set;}
    public bool IsWhatever {get; set;}
    public string Something {get; set;}
    public int SomeOtherId {get; set;}
}

And one instance, thus:

var p = new Product
                    {
                        Id = 1,
                        IsWhatever = false,
                        Something = "Pony",
                        SomeOtherId = 5
                    };

and another:

var newP = new Product
    {
        Id = 1,
        IsWhatever = true
    };

To get the differences between these, i'm doing stuff that includes this:

var oldProps = p.GetType().GetProperties();
var newProps = newP.GetType().GetProperties();

// snip 
foreach(var newInfo in newProps)
{
    var oldVal = oldInfo.GetValue(oldVersion, null);
    var newVal = newInfo.GetValue(newVersion,null);
}

// snip - some ifs & thens & other stuff

and it's this line that's of interest

var newVal = newInfo.GetValue(newVersion,null);

Using the example objects above, this line would give me a default value of 0 for SomeOtherId (same story for bools & DateTimes & whathaveyou).

What i'm looking for is a way to have newProps include only the properties that are explicitly specified in the object, so in the above example, Id and IsWhatever. I've played about with BindingFlags to no avail.

Is this possible? Is there a cleaner/better way to do it, or a tool that's out there to save me the trouble?

Thanks.


Solution

  • I ended up fixing the issue without using reflection (or, not using it in this way at least).

    It goes, more or less, like this:

    public class Comparable
    {
        private IDictionary<string, object> _cache;
    
        public Comparable()
        {
            _cache = new Dictionary<string, object>();
        }
    
        public IDictionary<string, object> Cache { get { return _cache; } }
    
        protected void Add(string name, object val)
        {
            _cache.Add(name, val);
        }
    }
    

    And the product implementation goes to this:

    public class Product : Comparable
    {
        private int _id;
        private bool _isWhatever;
        private string _something;
        private int _someOtherId;
    
        public int Id {get { return _id; } set{ _id = value; Add("Id", value); } }
        public bool IsWhatever { get { return _isWhatever; } set{ _isWhatever = value; Add("IsWhatever ", value); } }
        public string Something {get { return _something; } set{ _something = value; Add("Something ", value); } }
        public int SomeOtherId {get { return _someOtherId; } set{ _someOtherId = value; Add("SomeOtherId", value); } }
    }
    

    And the comparison is then pretty straightforward

    var dic = new Dictionary<string, object>();
    
    foreach(var obj in version1.Cache)
    {
        foreach(var newObj in version2.Cache)
        {
            //snip -- do stuff to check equality
            dic.Add(....);
        }
    }
    

    Doesn't hugely dirty the model, and works nicely.