简体   繁体   中英

Create an object that represents the differences in values between two other objects

Assume the following class:

public class MyEntity
{
    public string FirstName;
    public string LastName;
}

I would like to compare two instances of MyEntity , and create a new MyEntity instance that contains only the differences in values between the two other instances. Properties that are equal will result a null value in the new object.

for example, the I would like the following code:

MyEntity entity1 = new MyEntity() { FirstName = "Jon", LastName = "Doh" };
MyEntity entity2 = new MyEntity() { FirstName = "Jon", LastName = "The Great" };
MyEntity diffEntity = CreateDiffEntity(entity1, entity2);  // TODO 

to result with the following diffEntity values:

{
    FirstName: null,
    LastName: "The Great"
}

We can assume that all properties are nullable.

In case the values don't match, the new object should contain the value of the second object's property.

Please assume I have many types of entities, with different properties definitionsm
So I need a solution that can be used on other class types than MyEntity , and that won't require changes when new properties are added to the classes.

The final goal is to enable a client mobile application to send a DTO that contains only the changes made to an entity, to a ASP.NET MVC WebAPI server application.

How can this be properly done?

You could use Reflection to solve this. The basic gist of it is:

    public void Compare(object first,object second, object result)
    {
        Type t = first.GetType();
        PropertyInfo[] propertyInfoList =  t.GetProperties();

        foreach (PropertyInfo propertyInfo in propertyInfoList)
        {
            object value1=  propertyInfo.GetValue(first, null);
            object value2 = propertyInfo.GetValue(second, null);

            if (value1 != value2)
            {
                propertyInfo.SetValue(result, value1, null);
            }
            else
            {
               propertyInfo.SetValue(result, null, null);
            }

        }
    }

And then use it like this:

MyType result = new MyType();
Compare(object1,object2, result);

It could be used as an extension method or a member on one of your entities.

There's a big problem with this whole approach: you can't set anything to null . You should probably just be sending the full entity or, if you have interface(s) that only allow editing a subset of the properties, make a DTO for each interface with just the changes that can happen there.


Anyway, just because it was ripe for some easy improvement, this is a generic, and slightly modified, solution based on BrianV's solution . (using object.Equals instead of != allows for things to be compared by their values, not just their identities)

public T Compare<T>(T first, T second) where T : new()
{
    T result = new T();
    Type t = typeof(T);
    PropertyInfo[] propertyInfoList =  t.GetProperties();

    foreach (PropertyInfo propertyInfo in propertyInfoList)
    {
        object value1 = propertyInfo.GetValue(first, null);
        object value2 = propertyInfo.GetValue(second, null);

        if (!object.Equals(value1, value2))
            propertyInfo.SetValue(result, value2, null);
    }

    return result;
}

Use it like:

MyEntity entity1 = new MyEntity() { FirstName = "Jon", LastName = "Doh" };
MyEntity entity2 = new MyEntity() { FirstName = "Jon", LastName = "The Great" };
MyEntity diffEntity = Compare(entity1, entity2);

Here you go:

    static public T CreateDiffEntity<T>(T entity1, T entity2) where T : new()
    {
        T result = new T();
        foreach (var property in typeof(T).GetProperties())
        {
            var valuePropertyEntity1 = property.GetValue(entity1);
            var valuePropertyEntity2 = property.GetValue(entity2);
            if (!valuePropertyEntity1.Equals(valuePropertyEntity2))
                property.SetValue(result, valuePropertyEntity2);
            else
                property.SetValue(result, null);
        }
        return result;
    }

You can solve your issue like this:

public MyEntity CreateDiffEntity(MyEntity entity1, MyEntity entity2) {
    MyEntity diff = new MyEntity();
    diff.FirstName = !entity1.FirstName.equals(entity2.FirstName) ? entity2.FirstName : string.Empty;
    diff.LastName = !entity1.LastName.equals(entity2.LastName) ? entity2.LastName : string.Empty;
    return diff;
}

you can do it in the object initializer

MyEntity entity1 = new MyEntity() { FirstName = "Jon", LastName = "Doh" };
MyEntity entity2 = new MyEntity() { FirstName = "Jon", LastName = "The Great" };

MyEntity diffEntity = new MyEntity
     {
         FirstName = (entity1.FirstName == entity2.FirstName) ? null : entity2.FirstName,
         LastName = (entity1.LastName == entity2.LastName) ? null : entity2.LastName
     };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM