如何复制ref类型(deepcopy)?

时间:2009-05-10 17:39:01

标签: c# .net

我在集合中有一个接受IEnumerable的构造函数。我想使用项目枚举和创建新集合,但不引用相同的项目。项目可以是值和参考类型:

CustomCollection cc = new CustomCollection (IEnumerable<T> items)
{
    foreach (var item in items)
    {
        this.Add(item); // justs adds the reference for ref types.
    }
}

编辑:.NET集合具有相同的方法,并且不执行深层复制。为什么你想要一个引用与原始元素相同元素的集合?

6 个答案:

答案 0 :(得分:3)

如果有问题的类支持序列化,您可以将集合序列化为临时流,并将它们反序列化为新集合。

有些类支持ICloneable,但其确切的功能由程序员决定。它可能是一个深层拷贝,也可能不是。

当然,并非所有类都支持序列化或克隆,因此您无法对所有类型进行操作。

您需要为此设置一些限制。

答案 1 :(得分:2)

如果对象是可序列化的,您可以制作如下的深层副本:

 private object GetCopy(object original)
 {
     if (original == null)
     {
         return null;
     }

     object result;
     using (MemoryStream stream = new MemoryStream())
     {
         BinaryFormatter formatter = new BinaryFormatter();
         formatter.Serialize(stream, original);
         stream.Position = 0;
         result = formatter.Deserialize(stream);
         stream.Close();
     }
     return result;
 }

答案 2 :(得分:0)

我认为如果您的项目支持ICloneable接口(正确实现接口函数),您将能够调用创建深层副本的.clone函数。

答案 3 :(得分:0)

执行深层复制的效果差别很大,这就是CLR不会自动提供深层复制的原因。例如,想象一下,如果您的深层副本复制了对象,这些对象包含操作系统管理的资源(如SQL连接,套接字,自定义GDI画笔等),那么会发生什么。

你真的需要坚持使用上面建议的方法。如果您认为您信任源以正确实现接口,请检查T是否为ICloneable。如果不是(信任源或T不可克隆),则检查对象是否标记为ISerializable或具有Seri​​alizableAttribute,然后序列化/反序列化为新对象。

如果T不可复制或可序列化,那么您可能应该抛出异常而不是尝试进行深层复制。

答案 4 :(得分:-2)

你做不到。并非所有对象都支持类似克隆的方法。

答案 5 :(得分:-2)

我不知道语法,因为我没有使用它很多,但是这可能不会用Reflection完成吗?我意识到反射通常会导致性能损失,但您可能会做一些切换案例的事情,如下所示:

(伪代码)

if(item.isValueType) {
    newCol.Add(item)
} elseif(item.isRefType && item.SupportsICloneable) {
    newCol.Add(item.clone())
} else {
     doReflectionCopy()
}

您还可以为可序列化检查添加代码,并包含Frederik的方法。