【问题标题】:Update the base class property while deep cloning深度克隆时更新基类属性
【发布时间】:2016-03-30 14:54:40
【问题描述】:

我有以下基类

public class BaseEntity
{
   public Guid Id{get; set;}
   public string Name{get; set;}
}

我有许多继承自这个基类的子类。例如:

public Class Employee : BaseEntity
{
   public string UserId {get; set;} 
   public Role EmpRole {get; set;}
   public IList<Department> EmpDepartment {get; set;}
}

public class Role : BaseEntity
{
   public string Description{get; set;}
}

public Class Department : BaseEntity
{
   Public int NumOfEmployees {get; set;}
}

现在我需要创建员工对象的深层副本,并且必须更新从 BaseEntity 类继承的所有属性的 Id 字段。

我正在使用以下代码来实现它,但它不起作用:

public static T DeepClone<T>(T obj)
{
    IFormatter formatter = new BinaryFormatter();
    Stream stream = new MemoryStream();
    using (stream)
    {
        formatter.Serialize(stream, obj);
        stream.seek(0, SeekOrigin.Begin);
        var newObj = (T)formatter.Deserialize(stream);
        return updateClone(newObj);
    }
}

public static T UpdateClone<T>(T obj)
{
     var newObj = obj;
     foreach (PropertyInfo p in obj.GetType().BaseType.GetProperties())
     {
         if(p.Name.ToString().ToLower() = "id")
         {
             p.SetValue(newObj,Guid.NewGuid());
         }
     }

    return newObj;
}

这将更新 Id Employee。

但我还需要更新 Employee 内部所有属性的 ID。

谁能帮我解决这个问题?

已编辑:我已经尝试过遍历所有属性并更新 Id 的技术,但我使用的对象非常大,并且使用这种方法,代码的性能会受到很大影响。在某些情况下,完成该过程大约需要几分钟。我正在寻找更好的方法来解决这个问题。

【问题讨论】:

  • 另外,您可以使用复制构造函数模式,它适用于继承,但是如果您有很多类,它会变得乏味,因为您必须记住为所有这些类实现复制构造函数。只是一个想法。
  • 是的,我有很多课程,所有课程都有很多字段。我已经遍历了所有属性并更新了 id,但是我在性能上受到了很大的影响。
  • 好吧,UpdateClone&lt;T&gt; 仍然循环遍历所有属性,所以这仍然不是更好。如果您需要更新每种类型的大量属性,您最终会在UpdateClone&lt;T&gt; 中遇到大量特殊情况,这看起来也不是很好。在这一点上,我会去中心化它。你必须达到一个平衡,很多地方相同的代码 -> 集中/抽象。一个地方,很多特殊情况 -> 去中心化。
  • 谢谢弗兰克。我必须在很多类中更新单个属性“Id”。课程的深度可以达到第 n 级。我正在考虑创建单独的 Updater 类以在克隆对象后更新属性,但这不会使我的代码保持通用性。如果有更好的方法,请告诉我。
  • 只有id 还是有其他值需要更新?如果只是id,您可以将接口放在相关类上,并进行通用约束。如果是这种情况,我可以向您展示相对简单的方法。

标签: c# .net asp.net-mvc-4 deep-copy system.reflection


【解决方案1】:

你只是循环遍历该对象的基础属性,你应该遍历对象上存在的所有属性,然后更新它们

类似这样的:

public static T UpdateClone<T>(T obj)
{
    var newObj = obj;
    foreach (PropertyInfo p in obj.GetType().BaseType.GetProperties())
    {
        if (p.Name.ToString().ToLower() == "id")
        {
            p.SetValue(newObj, Guid.NewGuid());
        }
    }

    foreach (PropertyInfo pInfo in obj.GetType().GetProperties())
    {
        var propertyObject = pInfo.GetValue(obj);
        if (propertyObject != null)
        {
            if (propertyObject is IEnumerable && !(propertyObject is string))
            {
                foreach (object p in (propertyObject as IEnumerable))
                {
                    UpdateClone(p);
                }
            }
            else
            {
                foreach (PropertyInfo p in propertyObject.GetType().BaseType.GetProperties())
                {
                    if (p.Name.ToString().ToLower() == "id")
                    {
                        p.SetValue(propertyObject, Guid.NewGuid());
                    }
                }
            }
        }
    }
  return newObj;
}

【讨论】:

  • 谢谢,我已经尝试过这种方法。这种方法对性能的影响很大。我使用的对象非常大,有时克隆过程本身大约需要几分钟才能完成。我正在寻找更好的方法。
  • 如果是这种情况,我建议研究原型设计模式,也许这会有所帮助sourcemaking.com/design_patterns/prototype
猜你喜欢
  • 1970-01-01
  • 2010-10-25
  • 1970-01-01
  • 2012-01-05
  • 2017-09-01
  • 2010-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多