J'ai une chose étrange où un code que je suis en train de modifier à la fois la copie et la liste d'origine. J'ai réduit le problème autant que possible pour ne montrer l'erreur que dans un seul fichier. Bien que mon exemple du monde réel nous soit beaucoup plus complexe ... mais à la racine de tout cela, c'est le problème.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestingRandomShit
{
class Program
{
private static string rawInput;
private static List<string> rawList;
private static List<string> modifiedList;
static void Main(string[] args)
{
rawInput = "this is a listing of cats";
rawList = new List<string>();
rawList.Add("this");
rawList.Add("is");
rawList.Add("a");
rawList.Add("listing");
rawList.Add("of");
rawList.Add("cats");
PrintAll();
modifiedList = ModIt(rawList);
Console.WriteLine("\n\n**** Mod List Code has been run **** \n\n");
PrintAll();
}
public static List<string> ModIt(List<string> wordlist)
{
List<string> huh = new List<string>();
huh = wordlist;
for (int i = 0; i < huh.Count; i++)
{
huh[i] = "wtf?";
}
return huh;
}
//****************************************************************************************************************
//Below is just a print function.. all the action is above this line
public static void PrintAll()
{
Console.WriteLine(": Raw Input :");
Console.WriteLine(rawInput);
if (rawList != null)
{
Console.WriteLine("\n: Original List :");
foreach (string line in rawList)
{
Console.WriteLine(line);
}
}
if (modifiedList != null)
{
Console.WriteLine("\n: Modified List :");
foreach (string wtf in modifiedList)
{
Console.WriteLine(wtf);
}
Console.ReadKey();
}
}
}
}
En gros, j'ai trois variables .... une chaîne et deux List . Le code original dose un peu de tokenisation sur la chaîne, mais pour cette démo, j'utilise simplement List.Add () pour le simuler afin de le rendre simple à lire.
J'ai donc maintenant une chaîne et une liste avec un seul mot dans chaque élément.
C'est la partie déroutante que je ne comprends pas .. Je sais qu'elle a quelque chose à faire avec des références mais je ne peux pas savoir comment l'adapter.
Il y a une méthode que j'ai appelée ModIt () ... il prend simplement dans une liste puis crée une liste complètement nouvelle appelée huh, copie la liste originale sur la nouvelle liste puis change chaque ligne en hein à "wtf?".
Maintenant si je comprends bien .. Je devrais me retrouver avec 3 variables ...
1) une chaîne 2) une liste avec un mot différent dans chaque élément 3) une liste de la même longueur que l'autre avec chaque élément étant "wtf?"
Mais, que se passe-t-il, c'est que j'essaye d'imprimer les deux listes qu'ils ont tous les deux mis à "WTF?" ".... alors ouais ... wtf mec? Je suis super confus. Je veux dire dans le ModIt, je construis même une toute nouvelle chaîne plutôt que de modifier celle qui est transmise, mais cela ne semble pas affecter quoi que ce soit.
Ceci est la sortie ...
: Raw Input: ceci est une liste de chats
: Liste d'origine: ceci est une liste de chats
**** Le code de la liste des mods a été exécuté ****
: Raw Input: ceci est une liste de chats
: Liste d'origine: wtf? wtf? wtf? wtf? wtf? wtf?
: Liste modifiée: wtf? wtf? wtf? wtf? wtf? wtf?
3 Réponses :
huh = wordlist; ne copie pas les éléments de wordlist dans une nouvelle liste, il copie la référence dans le même objet occupé par wordlist (c'est-à-dire huh et wordlist puis pointez sur le même objet en mémoire).
Si vous voulez une copie, le moyen le plus simple pour en produire un utilise LINQ:
List<string> huh = wordlist.ToList();
Notez que ce sera une "copie superficielle". Si votre liste stocke des objets de référence, l'ancienne et la nouvelle liste stockeront des références aux mêmes objets.
Voir ici pour plus d'informations sur la valeur par rapport aux types de référence, puis ici si vous avez besoin d'une copie profonde.
Depuis tout ce que vous ' faire est de remplacer la valeur à un index de la liste, j'imagine qu'une copie superficielle convient.
Juste une remarque: en raison de la nature immuable des chaînes dans .NET, cela fonctionnera comme prévu, mais cela peut apporter des résultats intéressants si la liste contient un objet qui a une propriété de chaîne par exemple.
Merci les gars .. Je ne peux pas accepter de réponse car elle a été publiée si rapidement ... mais cela fonctionne et le lien que vous m'avez donné est utile. Donc merci!
John a déjà commenté le code défectueux:
//imagine the list stores people, the age of the first //person in the list is 27, and we increment it List1[0].PersonAge++; //list2 is a different list but refers to the same people objects //this will print 28 Console.Out.WriteLine(list2[0].PersonAge);
Ici, vous créez une nouvelle liste, puis la jetez et attachez votre référence hein à votre ancienne liste, donc hein et wordlist font référence à la même chose ..
Je voulais juste souligner la manière non LINQ de copier une liste:
List<string> huh = new List<string>(wordlist);
Passer l'ancienne liste dans le constructeur de la nouvelle liste; list a un constructeur qui prend une collection d'objets à stocker dans la nouvelle liste
Vous avez maintenant deux listes, et initialement elles font toutes deux référence aux mêmes chaînes, mais parce que les chaînes ne peuvent pas être modifiées, si vous commencez à changez les chaînes à l'intérieur de la liste (plutôt que de simplement les mélanger ou de les supprimer de la liste), de nouvelles seront créées
Si un point intéressant cependant; vous aurez 2 listes pointant vers les mêmes objets donc si vous avez, dans le futur, le même scénario avec des objets qui peuvent être modifiés et que vous changez l'objet dans une liste, cela changera également dans l'autre liste:
List<string> huh = new List<string>();
huh = wordlist;
C'est ce que nous entendons par copie superficielle
Votre problème vient du fait qu'en C # nous avons des types de référence et des types de valeur .
Les types de valeur peuvent recevoir des valeurs par l'opérateur d'affectation directe ( = ), mais pour les types de référence, c'est différent. Les types de référence ne stockent pas les données réelles elles-mêmes, ils stockent un emplacement en mémoire où les données sont conservées. Comme des pointeurs, si vous venez du monde C.
Jetez un œil à IClonable . Lisez également Paramètre passant par Jon Skeet , il donne une bonne description des types de valeur et de référence. < / p>
C'est parce que
huh = wordlist;vous faites une copie de référence