List <T>的深层副本

tho*_*234 15 c# deep-copy

我正在尝试制作通用列表的深层副本,并且想知道是否有任何其他方法然后创建复制方法并实际上一次复制每个成员.我有一个看起来像这样的课程:

public class Data
{            
    private string comment;
    public string Comment
    {
        get { return comment; }
        set { comment = value; }
    }

    private List<double> traceData;
    public List<double> TraceData
    {
        get { return traceData; }
        set { traceData = value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

我有一份上述数据清单,即List<Data>.我要做的是将List子集的跟踪数据绘制到图形上,可能需要对数据进行一些缩放或扫描.我显然不需要在列表中绘制所有内容,因为它们不适合屏幕.

我最初尝试使用该List.GetRange()方法获取列表的子集,但似乎底层List<double>是浅层复制而不是深度复制.当我使用List.GetRange()再次获取子集时,我获得了先前修改过的数据,而不是其他地方检索到的原始数据.

任何人都可以给我一个如何处理这个问题的方向吗?非常感谢.

mqp*_*mqp 10

在C#中处理此问题的惯用方法是ICloneable在您上面实现Data,并编写一个Clone执行深层复制的Enumerable.CloneRange方法(然后可能是一个可以立即克隆部分列表的方法.)没有任何内置技巧或框架方法使它更容易.

除非记忆和性能是一个真正的问题,否则我建议您尽量重新设计它以对不可变Data对象进行操作.它会变得简单得多.

  • +1:immutable实际上是唯一的方法:)如果用户不需要索引访问`List <double>`,那么一个简单的不可变堆栈就足够了. (2认同)
  • [IClonable现在几乎被认为是一个坏主意](http://stackoverflow.com/questions/536349/why-no-icloneablet) (2认同)

Sur*_*amy 6

你可以试试这个

    public static object DeepCopy(object obj)
    {
        if (obj == null)
            return null;
        Type type = obj.GetType();

        if (type.IsValueType || type == typeof(string))
        {
            return obj;
        }
        else if (type.IsArray)
        {
            Type elementType = Type.GetType(
                 type.FullName.Replace("[]", string.Empty));
            var array = obj as Array;
            Array copied = Array.CreateInstance(elementType, array.Length);
            for (int i = 0; i < array.Length; i++)
            {
                copied.SetValue(DeepCopy(array.GetValue(i)), i);
            }
            return Convert.ChangeType(copied, obj.GetType());
        }
        else if (type.IsClass)
        {

            object toret = Activator.CreateInstance(obj.GetType());
            FieldInfo[] fields = type.GetFields(BindingFlags.Public |
                        BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (FieldInfo field in fields)
            {
                object fieldValue = field.GetValue(obj);
                if (fieldValue == null)
                    continue;
                field.SetValue(toret, DeepCopy(fieldValue));
            }
            return toret;
        }
        else
            throw new ArgumentException("Unknown type");
    }
Run Code Online (Sandbox Code Playgroud)

感谢DetoX83 关于代码项目的文章.

  • 几乎无瑕疵.但就像我的情况一样,你有mscorlib或当前程序集之外的对象数组,你需要使用`elementType = Type.GetType(type.AssemblyQualifiedName.Replace("[]",string.Empty)); ` (2认同)

Xel*_*lom 5

如果IClonable的方式对你来说太棘手了.我建议转换成某种东西然后回来.它可以使用BinaryFormatter或像Servicestack.Text这样的Json转换器来完成,因为它是.Net中最快的一个.

代码应该是这样的:

MyClass mc = new MyClass();
string json = mc.ToJson();
MyClass mcCloned = json.FromJson<MyClass>();
Run Code Online (Sandbox Code Playgroud)

mcCloned不会引用mc.