2009-07-31 10 views
13

У меня есть типизированный массив MyType[] types; , и я хочу сделать и независимую копию этого массива. Я пробовал этоC# Копировать массив по значению

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

types2 = types ; 

но это создает ссылку на первую. Затем я попробовал

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

, но у меня та же проблема: изменение значения в первом массиве также изменяет значение в копии.

Как я могу сделать полностью независимую или глубокую копию массива, IList или IEnumerable?

ответ

9

Внедрить метод clone в MyType, используя защищенный метод MemberwiseClone (выполняет мелкую копию) или используя метод глубокого клонирования. Вы можете заставить его реализовать 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(); 
    } 
} 

Вы должны это сделать, потому что в то время как новый массив создаются при использовании Array.Copy копирует ссылки, а не объекты, указанные. Каждый тип отвечает за само копирование.

+1

Microsoft говорит: [Мы рекомендуем ICloneable не быть реализованы в общественных API,] (http://msdn.microsoft.com/en-us/library/system.icloneable (v = против .110) .aspx), потому что он не задает глубину и семантику неглубокой копии. Лучше создайте собственный интерфейс IDeepCopyable. – Wilbert

11

На основании первого сообщения все, что ему нужно, это «независимая копия массива». Изменения в массиве shallowCopy не появятся в массиве types (что означает назначение элемента, что на самом деле является тем, что он показал выше, несмотря на то, что он произнес «глубокую копию»). Если это соответствует вашим потребностям, оно будет иметь лучшую производительность.

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

Он также упоминает о «глубокой копии», которая будет отличаться для изменяемых типов, которые не являются рекурсивными агрегатами значения типа примитивов. Если MyType реализует ICloneable, это работает отлично подходит для глубокой копии:

MyType[] deepCopy = (MyType[])Array.ConvertAll(element => (MyType)element.Clone()); 
6

Если ваш типа сериализует вы можете использовать методы сериализации, чтобы получить копию массива (в том числе глубоких копий предметов):

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); 
+0

мой тип не является сериализуемым = ( – JOBG

+0

Это милый !!! –

3

Я хотел сделать то же самое: сделать копию массива по значению для таких вещей, как сортировка, так что я мог бы л ater повторно инициализирует другой массив temp с исходным исходным массивом. Изучив это, я обнаружил, что это невозможно сделать так просто. Итак, я сделал обходной путь. Я буду использовать свой собственный код ниже:

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]; 
} 

planetNames это мой источник массива. tempNames - это массив, который позже я буду сортировать независимо от имени planetNames. Я проверил это, и этот код не сортирует planetNames, когда я сортирую tempNames, которого я пытался достичь.

0

Я нашел, если вы просто хотите простой массив символов копии, вы можете обмануть 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; 

} 

, кажется, работает для меня, но если кто-то не согласен, пожалуйста, дайте мне знаю :)

+2

char - это тип значения. Это будет работать по-разному для ссылочных типов. – Odrade

1

Если вы хотите создать копию всего массива со ссылками на объекты в старом массиве (или если у вас есть массив объектов типа значения) , Простое решение

var newArray = oldArray.ToArray() 

Если вы хотите глубокой копии вы должны иметь метод, который копирует один объект вашего типа (например, public MyType Copy(MyType obj)). Тогда решение будет выглядеть

var newArray = oldArray.Select(x => Copy(x)).ToArray() 
+0

Чтобы уточнить, 'Copy (x)' является пользовательской реализацией, правильно? – Thor

+1

Да, нет способа выполнить глубокую копию объекта любого типа. Существует [MemberwiseClone] (https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone (v = vs.110) .aspx) в любом объекте, но он защищен и создает только мелкую копию (копия самого объекта, но не создает новые копии полей ссылочного типа), а не глубокую копию. – renadeen

Смежные вопросы