2009-07-31 18 views
13

Mam tablicę wpisaną MyType[] types; i chcę utworzyć niezależną kopię tej tablicy. próbowałem tegoC# Kopiuj tablicę według wartości

ale to utworzyć odniesienie do pierwszego. Następnie spróbowałem, ale mam ten sam problem: zmiana wartości w pierwszej tablicy zmienia również wartość w kopii.

Jak mogę utworzyć całkowicie niezależną lub głęboką kopię tablicy, ILIST lub IEnumerable?

Odpowiedz

9

Wprowadź metodę klonowania na MyType, używając metody chronionej MemberwiseClone (wykonuje płytką kopię) lub używając techniki głębokiego klonowania. Możesz go zaimplementować w programie ICloneable, a następnie napisać kilka metod rozszerzeń, które sklonują kolekcję odpowiadającą.

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

Musisz to zrobić, ponieważ podczas gdy nowa tablica jest tworzony podczas korzystania Array.Copy kopiuje referencje, a nie obiekty przywoływane. Każdy typ jest odpowiedzialny za samo kopiowanie.

+1

Microsoft mówi: [zalecamy ICloneable nie być realizowane w publicznych API] (http://msdn.microsoft.com/en-us/library/system.icloneable (v = vs .110) .aspx), ponieważ nie określa semantyki głębokiej względem płytkiej kopii. Lepiej stwórz własny interfejs IDeepCopyable. – Wilbert

11

Na podstawie pierwszego wpisu wystarczy tylko "niezależna kopia tablicy". Zmiany w samej macierzy shallowCopy nie pojawią się w tablicy types (co oznacza przypisanie elementów, co tak naprawdę pokazał powyżej pomimo "głębokiej kopii"). Jeśli to odpowiada Twoim potrzebom, będzie to miało najlepszą wydajność.

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

On również wspomina o „głęboką kopię”, która byłaby inna dla modyfikowalnych rodzajów, które nie są rekurencyjne agregaty wartość typu prymitywów. Jeśli MyType realizuje ICloneable ta działa świetnie na głęboką kopię:

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

Jeśli typ jest serializacji można stosować techniki serializacji aby otrzymać kopię swojej tablicy (w tym głębokich kopii pozycjach):

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

aby go użyć:

MyType[] items = new MyType[2]; 
// populate the items in the array 

MyType[] copies = (MyType[])GetCopy(items); 
+0

Mój typ nie jest możliwy do serializacji = ( – JOBG

+0

To jest słodkie !!! –

3

chciałem zrobić to samo: wykonaj kopię tablicy przez wartość dla rzeczy jak sortowanie, tak że mogłem l ater reinitialize inną tablicę temp z oryginalną tablicą źródłową. Po zbadaniu tego stwierdziłem, że nie można tego zrobić tak prosto. Tak, zrobiłem obejście. Użyję mój własny kod poniżej:

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 jest moją tablicą źródła. tempNames to tablica, którą później sortuję niezależnie od planetNames. Przetestowałem to i ten kod nie sortuje planetNames kiedy sortuję tempNames, co właśnie próbowałem osiągnąć.

0

Znalazłem jeśli chcesz tylko prosta tablica char kopiowaniem można oszukać C# do robienia kopii według wartości korzystając z char:

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; 

} 

wydaje się działać dla mnie, ale jeśli ktoś nie zgadza proszę dać mi wiem :)

+2

char jest typem wartości. To będzie działać inaczej dla typów referencji – Odrade

7

dla niecierpliwych:

newarray = new List<T>(oldarray).ToArray(); 
1

Jeśli chcesz utworzyć kopię tylko tablicę z odwołaniami do obiektów w starej tablicy (lub jeśli masz tablicę obiektów typu value) , najprostszym rozwiązaniem jest

var newArray = oldArray.ToArray() 

Jeśli potrzebujesz głębokiej kopii, powinieneś mieć metodę, która kopiuje pojedynczy obiekt twojego typu (np. public MyType Copy(MyType obj)). Wtedy rozwiązaniem będzie wyglądać

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

Aby wyjaśnić, 'Kopiuj (x)' jest niestandardową implementacją, prawda? – Thor

+1

Tak, nie ma metody wykonywania głębokiej kopii obiektu dowolnego typu. [MemberwiseClone] (https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone (v = vs.110) .aspx) w dowolnym obiekcie, ale jest chroniony i tworzy tylko płytką kopię (kopię samego obiektu, ale nie tworzy nowych kopii pól odniesienia), a nie kopię w wersji głębokiej. – renadeen

Powiązane problemy