2010-01-13 9 views
3

J'ai un List<T> et je fais ce qui suit:C# retour objet de tableau laisse pointer à l'élément Array

var myObj = List[2]; //Return object at position 2 
myObj.Name = "fred"; //If you look at List[2] its name has changed to fred 

J'ai essayé les suivants, mais il met à jour encore l'élément dans la liste

var newObj = new MyObj(); 
var myObj = List[2]; //Return object at position 2 
newObj = myObj; 
newObj.Name = "fred"; //If you look at List[2] its name has still changed to fred 

Comment puis-je éviter ce pointeur pour pouvoir mettre à jour les propriétés sans le mettre à jour dans la liste?

Répondre

1

Grands commentaires, merci, mais ce que j'ai mis en œuvre:

public MyObj Clone() 
    { 
     BinaryFormatter bFormatter = new BinaryFormatter(); 
     MemoryStream stream = new MemoryStream(); 
     bFormatter.Serialize(stream, this); 
     stream.Seek(0, SeekOrigin.Begin); 
     MyObj newObj = (MyObj)bFormatter.Deserialize(stream); 
     return newObj; 
    } 
3

Vous pouvez faire votre objet implémenter l'interface ICloneable en utilisant la méthode MemberwiseClone puis:

var myObj = List[2]; 
var newObj = myObj.Clone(); 
newObj.Name = "fred"; 

MISE À JOUR:

Comme indiqué dans la section des commentaires, il est recommandé de ne pas mettre en œuvre le ICloneable l'interface car elle ne spécifie pas si elle effectuera un clone peu profond ou profond. Ajoutez simplement une méthode Clone à votre classe.

+1

Les lignes directrices de conception-cadre contre la mise en œuvre conseille l'interface ICloneable. Fournissez simplement une méthode 'Clone'. – dtb

+1

L'idée de clonage est la bonne, mais n'implémentez pas ICloneable. Voir http://blogs.msdn.com/brada/archive/2003/04/09/49935.aspx pour plus de détails. –

+0

Existe-t-il un moyen rapide de copier toutes les propriétés sur le nouvel objet plutôt que de taper manuellement toutes les propriétés explicitement au cas où la classe obtiendrait une nouvelle propriété et la méthode clone oublie d'ajouter cette propriété à copier. – Jon

1

Que voulez-vous exactement faire de toute façon? Voulez-vous mettre à jour la propriété de l'objet dans la liste, ou voulez-vous un autre objet qui est une copie de l'objet dans la liste mais avec un nom différent? Au lieu de fournir une méthode de clonage, vous pouvez fournir un constructeur de copie.

var newObj = new MyObj(List[2]); 
newObj.Name = "fred"; 

Vous pourriez être en mesure de le faire en un seul appel, en fonction de ce que vous voulez faire. Si vous savez que vous allez toujours créer une copie avec juste un nom différent, vous voudrez peut-être faire quelque chose comme

var newObj = new MyObj(List[2],"fred"); 

et définir le nom lors de la construction. Mais sans créer explicitement un nouvel objet d'une manière ou d'une autre, vous ne pouvez pas faire ce que vous voulez. Sachez cependant que si vous avez une propriété qui est un autre objet, vous risquez de vous retrouver dans le problème de la 'copie en profondeur' (c'est pourquoi IClonable est déconseillé) comme quoi faites-vous quand vous avez besoin de copier cet objet? en toi nouveauObj? Est-ce que vous fournissez simplement une référence à la même instance? Ou copiez-vous cela aussi? Que faire si cet objet n'a pas de méthode clone/constructeur de copie, que faites-vous alors?

1

Jon. En C# les éléments de votre tableau sont stockés 'par référence', ce qui signifie que vous ne détenez pas une copie de l'objet dans le tableau que vous détenez une référence (un 'pointeur'). Lorsque vous récupérez l'élément, vous récupérez la référence, vous avez donc deux références au même objet. Comme vous n'avez qu'un objet lorsque vous mettez à jour la valeur, les deux références 'voient' la nouvelle valeur. Pour éviter cela, vous devez copier l'instance et il y a plusieurs façons de le faire. Comme Darin l'a mentionné, vous pouvez faire en sorte que l'objet implémente IClonable, vous pouvez également implémenter un constructeur de copie, ou vous pouvez créer un nouvel objet et remplir le nouveau à partir des anciennes données. Cependant, sachez qu'il y a des problèmes, le principal étant le problème de la 'copie profonde'. Si votre objet contient des références à d'autres objets, comment les copiez-vous? est-ce que vous copiez la référence ou est-ce que vous poursuivez les références vers le bas et «copiez-les en profondeur». Il n'y a pas de réponse unique à cela, juste le classique "ça dépend!"

2

Ceci n'a rien à voir avec les tableaux ou les listes en soi - c'est juste le mode de fonctionnement des types de référence.Voici une démonstration plus simple:

MyObj a = new MyObj(); 
MyObj b = a; 
a.Name = "Test"; 
Console.WriteLine(b.Name); // Will print "Test" 

listes et tableaux fonctionnent de la même manière - les valeurs stockées seront références (en supposant qu'ils sont des valeurs de type de référence) plutôt que les données de l'objet lui-même.

Vous voudrez peut-être lire mon article about reference types and value types pour plus d'informations.

Comme d'autres l'ont dit, si vous voulez vraiment des objets indépendants, vous aurez besoin de les cloner. Je suggérerais d'essayer de concevoir autour d'une autre manière cependant, personnellement.