C# 代码正在修改错误的变量。。。为什么?

C# 代码正在修改错误的变量。。。为什么?,c#,C#,我有一件奇怪的事情,我正在做的一些代码是修改副本和原始列表。。我已经尽可能地将问题归结为只在单个文件中显示错误。虽然我的现实世界的例子要复杂得多。。但问题的根源在于这一切 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TestingRandomShit { class Program

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

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();
            }
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
名称空间测试
{
班级计划
{
私有静态字符串输入;
私有静态列表;
私有静态列表修改列表;
静态void Main(字符串[]参数)
{
rawInput=“这是猫的列表”;
rawList=新列表();
添加(“本”);
原始列表。添加(“is”);
原始列表。添加(“a”);
添加(“列表”);
原始列表。添加(“of”);
添加(“猫”);
PrintAll();
modifiedList=ModIt(原始列表);
Console.WriteLine(“\n\n****模块列表代码已运行****\n\n”);
PrintAll();
}
公共静态列表修改(列表字列表)
{
List huh=新列表();
huh=词表;
for(int i=0;i
基本上,我有三个变量。。。。一个字符串和两个列表。原始代码对字符串进行了一些标记化,但是对于这个演示,我简单地使用List.Add()来伪造它,使其易于阅读

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

这是我不明白的令人困惑的部分。。我知道这与参考资料有关,但我不知道如何匹配它

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

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

1) 一串 2) 每个元素中有不同单词的列表 3) 与其他元素长度相同的列表,每个元素都是“wtf?”

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

这是输出

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

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

****Mod List代码已运行****

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

:原始列表:wtf?世界跆拳道联盟?世界跆拳道联盟?世界跆拳道联盟?世界跆拳道联盟?wtf

:修改列表:wtf?世界跆拳道联盟?世界跆拳道联盟?世界跆拳道联盟?世界跆拳道联盟?wtf


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

如果需要副本,最简单的方法是使用LINQ:

List<string> huh = wordlist.ToList();
List huh=wordlist.ToList();
请注意,这将是一个“浅拷贝”。如果列表存储引用对象,则旧列表和新列表都将存储对相同对象的引用

有关值与引用类型的更多信息,请参阅,如果需要深度副本,请参阅


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

John已经对错误代码发表了评论:

        List<string> huh = new List<string>();
        huh = 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
。同样值得一读的是,它对值和引用类型给出了很好的描述。

只是一个旁注:由于.NET中字符串的不可变性质,这将按预期工作,但是如果列表包含一个具有字符串属性的对象,它可以带来一些有趣的结果。谢谢大家。。我
//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);