代码之家  ›  专栏  ›  技术社区  ›  JOBG

按值复制数组

  •  14
  • JOBG  · 技术社区  · 16 年前

    我有一个类型化数组 MyType[] types; 我想制作这个数组的独立副本。我试过这个

    MyType[] types2 = new MyType[types.Length] ;
    
    types2 = types ;
    

    但这就产生了对第一个的引用。然后我尝试

    Array.Copy( types , types2 , types.Length ) ;
    

    但我也有同样的问题:更改第一个数组中的值也会更改副本中的值。

    如何对数组、IList或IEnumerable进行完全独立或深度复制?

    7 回复  |  直到 8 年前
        1
  •  9
  •   eulerfx    16 年前

    使用受保护的方法MemberWiseClone(执行浅复制)或使用深度克隆技术在MyType上实现克隆方法。您可以让它实现一个ICloneable,然后编写几个扩展方法来克隆相应的集合。

    interface ICloneable<T>
    {
        T Clone();
    }
    
    public static class Extensions
    {
        public static T[] Clone<T>(this T[] array) where T : ICloneable<T>
        {
            var newArray = new T[array.Length];
            for (var i = 0; i < array.Length; i++)
                newArray[i] = array[i].Clone();
            return newArray;
        }
        public static IEnumerable<T> Clone<T>(this IEnumerable<T> items) where T : ICloneable<T>
        {
            foreach (var item in items)
                yield return item.Clone();
        }
    }
    

    必须执行此操作,因为在使用数组时创建新数组时,复制它将复制引用,而不是复制引用的对象。每种类型都负责复制自己。

        2
  •  11
  •   Sam Harwell    16 年前

    基于第一篇文章,他所需要的只是“数组的独立副本”。改变到 shallowCopy 数组本身不会出现在 types 数组(意思是元素分配,这确实是他在上面展示的,尽管他说“深度复制”)。如果这符合你的需要,它将有最好的性能。

    MyType[] shallowCopy = (MyType[])types.Clone();
    

    他还提到了一个“深度复制”,对于不是基元递归值类型聚合的可变类型,这是不同的。如果 MyType 器具 ICloneable 这对深度复制非常有用:

    MyType[] deepCopy = (MyType[])Array.ConvertAll(element => (MyType)element.Clone());
    
        3
  •  8
  •   heltonbiker    10 年前

    对于不耐烦的人:

    newarray = new List<T>(oldarray).ToArray();
    
        4
  •  7
  •   Fredrik Mörk    16 年前

    如果类型是可序列化的,则可以使用序列化技术获取数组的副本(包括项目的深度副本):

    private static object GetCopy(object input)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, input);
            stream.Position = 0;
            return formatter.Deserialize(stream);
        }
    }
    

    使用它:

    MyType[] items = new MyType[2];
    // populate the items in the array
    
    MyType[] copies = (MyType[])GetCopy(items);
    
        5
  •  3
  •   Ryan Novack    13 年前

    我想做同样的事情:为排序之类的事情按值复制一个数组,这样我以后可以用原始源数组重新初始化另一个临时数组。经过研究,我发现这不可能这么简单。所以,我做了一个变通方案。我将使用我自己的代码:

    string[] planetNames = new string[] { "earth", "venus", "mars" };
    
    string[] tempNames = new string[planetNames.Length];
    
    for (int i = 0; i < planetNames.Length; i++)
    {
         tempNames[i] = planetNames[i];
    }
    

    行星名称 是我的源数组。 暴风雨的名字 是我稍后将独立于planetname排序的数组。我已经测试过了,但这个代码没有排序 行星名称 当我排序时 暴风雨的名字 这就是我想要达到的目标。

        6
  •  1
  •   renadeen    8 年前

    如果您只想创建一个引用了旧数组中对象的数组的副本(或者如果您有值类型对象的数组),最简单的解决方案是

    var newArray = oldArray.ToArray()
    

    如果您需要深度复制,您应该有一个复制您类型的单个对象的方法(例如 public MyType Copy(MyType obj) )那么解决方案看起来像

    var newArray = oldArray.Select(x => Copy(x)).ToArray()
    
        7
  •  0
  •   Flak714    12 年前

    我发现,如果您只需要一个简单的char数组拷贝,您可以使用char诱骗c按值进行拷贝:

    char[] newchararray = new char[desiredchararray.Length];
    
    for (int k = 0; k < desiredchararray.Length; k++)
    {
    
       char thecharacter = newchararray[k];
       newchararray[k] = thecharacter;
       oldchararray[k] = oldchararray[k] + 1;
    
    }
    

    似乎对我有用,但如果有人不同意,请告诉我:)