代码正在修改错误的变量..为什么

  • 本文关键字:变量 错误 修改 代码 c#
  • 更新时间 :
  • 英文 :


我有一件奇怪的事情,我正在做的一些代码正在修改副本和原始列表。。我已经尽可能地把问题归结为只在一个文件中显示错误。尽管我的现实世界的例子我们要复杂得多。。但这一切的根源在于问题。

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("nn**** Mod List Code has been run **** nn");
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();
}
}
}
}

基本上,我有三个变量。。。。一个字符串和两个列表。原始代码在字符串上添加了一些标记,但对于这个演示,我只是简单地使用List.Add()来伪造它,使其易于阅读。

所以我现在有一个字符串和一个列表,每个元素中只有一个单词。

这是我不理解的令人困惑的部分。。我知道这与参考文献有关,但我不知道如何适应。

有一个我称之为ModIt()的方法。。。它简单地接收一个列表,然后制作一个名为huh的全新列表,将原始列表复制到新列表上,然后将huh中的每一行都更改为"wtf?"。

现在,据我所知,我应该得到3个变量。。。

1) 字符串2) 每个元素中都有不同单词的列表3) a与其他元素长度相同的列表,每个元素都是"wtf?">

但是,发生的是,我试图打印出两个列表,它们都将每个元素设置为"WTF?"。。。。所以是的。。wtf人?我非常困惑。我的意思是,在ModIt中,我甚至构建了一个全新的字符串,而不是修改正在传递的字符串,但它似乎没有任何影响。

这是输出。。。

:原始输入:这是猫的列表

:原始列表:这是猫的列表

****Mod List Code已运行***

:原始输入:这是猫的列表

:原始列表:wtf?wtf?wtf?wtf?wtf?wtf?

:修改列表:wtf?wtf?wtf?wtf?wtf?wtf?

huh = wordlist;不会将wordlist的项复制到新列表中,而是将引用复制到wordlist占用的同一对象(即huhwordlist然后指向内存中的同一个对象)。

如果你想要一个副本,最简单的方法是使用LINQ:

List<string> huh = wordlist.ToList();

请注意,这将是一个"浅拷贝"。如果您的列表存储引用对象,则旧列表和新列表都将存储对相同对象的引用。

有关值与引用类型的更多阅读,请参阅此处,如果您需要深入的副本,请参阅这里。

由于您所要做的只是替换列表索引处的值,所以我认为浅拷贝是可以的。

John已经评论了错误代码:

List<string> huh = new List<string>();
huh = wordlist;

在这里,你制作了一个新的列表,然后把它扔掉,把你的参考huh附加到你的旧列表上,所以哈和单词列表都指同一个东西。。

我只是想指出复制列表的非LINQ方式:

List<string> huh = new List<string>(wordlist);

将旧列表传递到新列表的构造函数中;列表有一个构造函数,它将一组对象存储在新列表中

您现在有两个列表,最初它们都引用相同的字符串,但由于字符串无法更改,如果您开始更改列表中的字符串(而不仅仅是取消或从列表中删除它们),将创建新的

如果这是一个有价值的观点;你会有两个列表指向相同的对象,所以如果你在未来有相同的场景,有可以更改的对象,并且你在一个列表中更改了对象,它也会在另一个列表:

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

这就是我们所说的浅拷贝

您的问题来自于这样一个事实:在C#中,我们有引用类型

值类型值类型可以由直接赋值运算符(=)赋值,但对于引用类型则不同。引用类型不存储实际数据本身,而是在内存中存储数据所在的位置。就像指针一样,如果你来自C世界。

看看IClonable。另请阅读Jon Skeet传递的Parameter,它对值和引用类型进行了很好的描述。

最新更新