即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

列表的深层副本

栈溢出 thomas1234 106℃ 0评论
本文目录
[隐藏]

1.原始问题:Deep copy of List

I’m trying to make a deep copy of a generic list, and am wondering if there is any other way then creating the copying method and actually copying over each member one at a time. I have a class that looks somewhat like this:

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

    private List traceData;
    public List TraceData
    {
        get { return traceData; }
        set { traceData = value; }
    }
}

And I have a list of the above data, i.e List. What I’m trying to do is plot a trace data of the subset of List onto a graph, possibly with some scaling or sweeping on the data. I obviously don’t need to plot everything in the list because they don’t fit into the screen.

I initially tried getting the subset of the list using the List.GetRange() method, but it seems that the underneath List is being shallow copied instead of deep copied. When I get the subset again using List.GetRange(), I get previously modified data, not the raw data retrieved elsewhere.

Can anyone give me a direction on how to approach this? Thanks a lot.

2.被采纳答案

The idiomatic way to approach this in C# is to implement ICloneable on your Data, and write a Clone method that does the deep copy (and then presumably a Enumerable.CloneRange method that can clone part of your list at once.) There isn’t any built-in trick or framework method to make it easier than that.

Unless memory and performance are a real concern, I suggest that you try hard to redesign it to operate on immutable Data objects, though, instead. It’ll wind up much simpler.

3.其他高票答案

3.1.第1个答案

You can try this

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

Thanks to DetoX83 article on code project.

3.2.第2个答案

If IClonable way is too tricky for you. I suggest converting to something and back. It can be done with BinaryFormatter or a Json Converter like Servicestack.Text since it is the fastest one in .Net.

Code should be something like this:

MyClass mc = new MyClass();
string json = mc.ToJson();
MyClass mcCloned = json.FromJson();

mcCloned will not reference mc.

3.3.第3个答案

The most easiest (but dirty) way is to implement ICloneable by your class and use next extension method:

public static IEnumerable Clone(this IEnumerable collection) where T : ICloneable
{
    return collection.Select(item => (T)item.Clone());
}

Usage:

var list = new List { new Data { Comment = "comment", TraceData = new List { 1, 2, 3 } };
var newList = list.Clone();

3.4.第4个答案

another thing you can do is mark your class as serializable and use binary serialization.
Here is a working example

   public class Program
    {
        [Serializable]
        public class Test
        {
            public int Id { get; set; }
            public Test()
            {

            }
        }

        public static void Main()
        {   
            //create a list of 10 Test objects with Id's 0-10
            List firstList = Enumerable.Range(0,10).Select( x => new Test { Id = x } ).ToList();
            using (var stream = new System.IO.MemoryStream())

            {
                 var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                 binaryFormatter.Serialize(stream, firstList); //serialize to stream
                 stream.Position = 0;
                 //deserialize from stream.
                 List secondList = binaryFormatter.Deserialize(stream) as List; 
            }


            Console.ReadKey();
        }
    }

转载请注明:CodingBlog » 列表的深层副本

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情