2009-07-31 10 views
13

J'ai un tableau tapé MyType[] types; et je veux faire et copie indépendante de ce tableau. j'ai essayé ceciC# Copier tableau par valeur

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

types2 = types ; 

mais cela crée une référence à la première. J'ai alors essayé

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

mais j'ai le même problème: changer une valeur dans le premier tableau change aussi la valeur dans la copie.

Comment puis-je faire une copie complètement indépendante ou profonde d'un tableau, IList ou IEnumerable?

Répondre

9

Implémentez une méthode de clonage sur MyType, en utilisant la méthode protégée MemberwiseClone (effectue une copie superficielle) ou en utilisant une technique de clonage en profondeur. Vous pouvez lui faire implémenter un IClonable puis écrire plusieurs méthodes d'extensions qui cloneront la collection corresponsing.

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

Vous devez faire cela parce que tout un nouveau tableau est créé lorsque vous utilisez Array.Copy il copie les références, pas les objets référencés. Chaque type est responsable de se copier.

+1

Microsoft dit: [nous recommandons ICloneable pas être mis en œuvre dans les API publiques] (http://msdn.microsoft.com/en-us/library/system.icloneable (v = vs .110) .aspx) car il ne spécifie pas la sémantique de la copie profonde par rapport à la copie superficielle. Mieux vaut créer sa propre interface IDeepCopyable. – Wilbert

11

Basé sur le premier message, tout ce dont il a besoin est ceci pour "une copie indépendante du tableau". Les modifications du tableau shallowCopy lui-même n'apparaîtraient pas dans le tableau types (ce qui signifie l'affectation d'éléments, ce qui est vraiment ce qu'il a montré ci-dessus malgré la mention "copie en profondeur"). Si cela convient à vos besoins, il aura les meilleures performances.

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

Il mentionne aussi une « copie profonde » qui serait différent pour les types mutables qui ne sont pas des agrégats de type valeur récursives de primitives. Si le MyType implémente ICloneable, cela fonctionne très bien pour une copie complète:

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

Si votre type est sérialisable, vous pouvez utiliser des techniques de sérialisation pour obtenir une copie de votre tableau (y compris des copies complètes des articles):

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

pour l'utiliser:

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

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

mon type n'est pas sérialisable = ( – JOBG

+0

C'est gentil !!! –

3

Je voulais faire la même chose: faire une copie d'un tableau par valeur pour des choses comme le tri pour que je puisse l ater réinitialise un autre tableau temporaire avec le tableau source d'origine. Après avoir étudié cela, j'ai trouvé que cela ne pouvait pas être fait aussi simplement. Donc, j'ai fait une solution de contournement. Je vais utiliser mon propre code ci-dessous:

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 est mon tableau source. tempNames est le tableau que je trierai plus tard indépendamment de planetNames. J'ai testé ceci et ce code ne triera pas planetNames quand je trie tempNames qui est ce que j'essayais de réaliser.

0

Je l'ai trouvé si vous voulez juste un simple tableau de caractères copie vous pouvez duper C# en faire une copie en valeur à l'aide du charbon:

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; 

} 

semble fonctionner pour moi, mais si quelqu'un est en désaccord s'il vous plaît laissez-moi :) savoir

+2

char est un type de valeur Cela va fonctionner différemment pour les types de référence – Odrade

7

pour les impatients:

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

Si vous souhaitez créer une copie de tout un tableau avec des références à des objets dans le vieux tableau (ou si vous avez tableau d'objets de type valeur) , Est

var newArray = oldArray.ToArray() 

solution la plus simple Si vous voulez une copie profonde, vous devriez avoir une méthode qui copie unique objet de votre type (par exemple public MyType Copy(MyType obj)). Ensuite, la solution ressemblera

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

Pour clarifier, 'Copy (x)' est une implémentation personnalisée, n'est-ce pas? – Thor

+1

Oui, Il n'existe aucune méthode pour effectuer une copie en profondeur de l'objet de n'importe quel type. [MemberwiseClone] (https://msdn.microsoft.com/fr-fr/library/system.object.memberwiseclone (v = vs.110) .aspx) dans n'importe quel objet mais il est protégé et ne crée qu'une copie superficielle (copie de l'objet lui-même mais ne crée pas de nouvelles copies des types de champs de référence), pas de copie profonde. – renadeen

Questions connexes