【问题标题】:Clone ObservableCollection克隆 ObservableCollection
【发布时间】:2017-02-08 10:07:49
【问题描述】:

我有 ObservableCollection 和其他属性的课程。 所以看起来有点像这样:

public class A
{
   public int Id { get; set; }
   ...
   public object AValue {get; set;}
}

我想克隆这个类的对象。 AValue 属性可以是 ObservableCollection 或其他对象。当AValue 是 ObservableCollection 类型并且我尝试向其添加一些对象时,似乎克隆具有与原始对象相同的对象。如果我只对AValue 属性使用我的克隆方法,而不是A 类的对象,它可以工作。克隆我尝试使用的对象:

 private object Clone(object obj)
    {
        var t = obj.GetType();

        if (obj == null)
            return null;

        if (t.IsValueType || t == typeof(string))
        {
            return obj;
        }
        else if (t.IsGenericType)
        {
            if (obj is IList)
            {
                var c= typeof(ObservableCollection<>);
                var cType = type.GetGenericArguments().First();
                var gType = c.MakeGenericType(cType);
                var newC = (IList)Activator.CreateInstance(gType);

                foreach (var item in (IEnumerable)obj)
                    newC.Add(item);

                return newC;
            }
        }
        else if (t.IsClass)
        {
            object objV = Activator.CreateInstance(type);
            FieldInfo[] fields = t.GetFields(BindingFlags.Public |
                        BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (FieldInfo field in fields)
            {
                object fieldV = field.GetValue(obj);
                if (fieldValue == null)
                    continue;
                field.SetValue(objV, Clone(fieldV));
            }
            return obj;
        }
        throw new ArgumentException("Unknown type");
    }
}

编辑 谢谢你的回答。 我添加了您的代码@Sefe,但它仍然不起作用。我知道其他类型不会克隆,但我想先用列表来做。我不知道哪里错了。我得到 A 类对象,然后我克隆对象并将 A 类对象发送到对话框。我从克隆和原始更改集合和属性是相同的。 将 IClonable 接口添加到泛型列表中就足够了

 ObservableCollection<B> = new  ObservableCollection<B>();

public class B: Base, ICloneable
{
  ...
  public object Clone()
  {
    return this.MemberwiseClone();
  }

}

泛型类型可以从另一个类继承重要吗?

【问题讨论】:

  • 您的代码中可能存在错误。不是列表的泛型类型呢?它们不会被克隆。

标签: c#


【解决方案1】:

您正在克隆集合,但没有克隆其中的项目。要创建集合的深层克隆,您还需要克隆项目(如果可能):

foreach (var item in (IEnumerable)obj) {
    ICloneable cloneable = item as ICloneable;
    if (cloneable != null) {
        newC.Add(cloneable.Clone());
    }
    else {
        newC.Add(item);
    }
}

使用ICloneable 接口是.NET 框架中的内置方式,您可以期望framweork 方法在必要时识别它。所以这将是首选方式。如果您想重用自己现有的 Clone 方法,可以递归调用它:

foreach (var item in (IEnumerable)obj) {
    newC.Add(Clone(item));
}

更新(解决问题的编辑):

当您使用MemberwiseClone 时,所有字段和事件将被转移到克隆。 MemberwiseClone 创建一个 shallow 副本,以便传输字段和分配的事件处理程序。因此,如果您有包含其他引用类型的字段,这些将不会被克隆(即使它们是ICloneable)。此外,分配给原始的事件处理程序也将分配给克隆。

您的ICloneable.Clone 方法必须注意将克隆置于有效状态。由于有效内容因情况而异,因此 .NET 框架中没有自动深度克隆。调用MemberwiseClone 通常是一个好的开始,但是您必须随后处理包含的对象、事件处理程序等,以将您的浅层克隆“升级”为深层克隆。

【讨论】:

  • 当我经常需要深度复制集合时,我为容器编写了一个扩展。签名是public static TContainer CloneDeep&lt;TContainer, T&gt;( this TContainer r ) where T : ICloneable where TContainer: ICollection&lt;T&gt;, new()。普通的泛型都有一个new(),因此它适用于常见的列表等。该函数简单地遍历源容器和Clone()s 元素,将它们添加到克隆的容器中。请注意,字典需要克隆键和值的特殊处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-19
  • 1970-01-01
  • 2013-08-07
  • 1970-01-01
相关资源
最近更新 更多