【问题标题】:Create an object that represents the differences in values between two other objects创建一个表示其他两个对象之间值差异的对象
【发布时间】:2013-08-20 18:12:50
【问题描述】:

假设以下类:

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

我想比较MyEntity 的两个实例,并创建一个新的MyEntity 实例,其中只包含其他两个实例之间的值差异。相等的属性将在新对象中产生null 值。

例如,我想要以下代码:

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

产生以下diffEntity 值:

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

我们可以假设所有属性都可以为空。

如果值不匹配,新对象应包含第二个对象的属性值。

请假设我有许多类型的实体,具有不同的属性定义m
所以我需要一个可以在MyEntity以外的其他类类型上使用的解决方案,并且在将新属性添加到类时不需要更改。

最终目标是使客户端移动应用程序能够将仅包含对实体所做更改的 DTO 发送到 ASP.NET MVC WebAPI 服务器应用程序。

如何才能正确地做到这一点?

【问题讨论】:

  • 您是否已经尝试过任何事情并被卡住了,或者只是发布了一个问题并认为有人会为您做任何事情? :)
  • 如果它们不匹配,diffEntity 将采用第二个实体的值...?
  • 听起来是个有趣的问题,您可以在类构造函数中执行此操作,比较entity1entity2 的值。你有没有尝试过任何东西,或者这只是一个家庭作业问题?
  • diffEntity 如果不匹配,将采用第二个实体的值
  • 假设您要将属性更改为null。您的方法似乎不允许这样做。您可能需要重新考虑您的方法。

标签: c# reflection


【解决方案1】:

您可以使用反射来解决这个问题。它的基本要点是:

    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);
            }

        }
    }

然后像这样使用它:

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

它可以用作扩展方法或您的一个实体的成员。

【讨论】:

    【解决方案2】:

    整个方法存在一个大问题:您不能为null 设置任何内容。您可能应该只发送完整的实体,或者,如果您的接口只允许编辑属性的子集,请为每个接口创建一个 DTO,其中仅包含可能发生的更改。


    无论如何,只是因为它已经成熟,可以进行一些简单的改进,这是一个基于BrianV's solution 的通用且稍作修改的解决方案。 (使用object.Equals 而不是!= 允许通过它们的值来比较事物,而不仅仅是它们的身份)

    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;
    }
    

    像这样使用它:

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

    【讨论】:

      【解决方案3】:

      给你:

          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;
          }
      

      【讨论】:

        【解决方案4】:

        你可以这样解决你的问题:

        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;
        }
        

        【讨论】:

        • 你想要null,而不是string.Empty。请参阅 OP 的示例输出。
        • @tnw yepp,但这只是代码示例。 OP 可以自行替换为 null。
        【解决方案5】:

        你可以在对象初始化器中做到这一点

        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
             };
        

        【讨论】:

        • 我需要一个可以在MyEntity以外的其他类型上使用的解决方案,并且在将新属性添加到类时不需要更改
        • @Liel 那么布赖恩的解决方案可能就是您想要的。
        猜你喜欢
        • 1970-01-01
        • 2017-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-27
        • 1970-01-01
        • 2021-10-16
        • 2013-07-19
        相关资源
        最近更新 更多