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

时间:2019-01-07 06:36:06

标签: 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("\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();
            }
        }
    }
}

基本上,我有三个变量...。一个字符串和两个List。原始代码对字符串进行了一些标记化,但是对于此演示,我简单地使用List.Add()对其进行伪造以使其易于阅读。

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

这是我不理解的令人困惑的部分。我知道它与参考有关,但是我无法弄清楚如何适合它。

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

现在,据我所知..我应该以3个变量结束...

1)字符串 2)每个元素中包含不同单词的列表 3)与其他元素长度相同的列表,每个元素均为“ wtf?”

但是,发生的是那是我尝试同时打印出两个都将每个元素都设置为“ WTF”的列表吗?我很困惑。我的意思是在ModIt中,我什至构建了一个全新的字符串,而不是修改正在传递的字符串,但这似乎没有任何作用。

这是输出...

  

:原始输入内容:这是猫的清单

     

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

     

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

     

:原始输入内容:这是猫的清单

     

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

     

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

3 个答案:

答案 0 :(得分:12)

huh = wordlist;不会将wordlist的项目复制到新列表中,而是将 reference 复制到wordlist所占用的同一对象(即{ {1}}和huh然后指向内存中的同一对象。

如果要复制,最简单的生产方法是使用LINQ:

wordlist

请注意,这将是“浅副本”。如果您的列表存储引用对象,则旧列表和新列表都将存储对相同对象的引用。

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

由于您要做的就是替换列表索引中的值,因此我认为可以使用浅表副本。

答案 1 :(得分:5)

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

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

您在这里创建了一个新列表,然后将其丢弃,并将引用huh附加到旧列表中,所以呵呵和单词列表都指的是同一件事。

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

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

将旧列表传递到新列表的构造函数中; list具有一个构造函数,该构造函数将对象集合存储在新列表中

您现在有两个列表,并且最初它们都引用相同的字符串,但是由于不能更改字符串,因此,如果您开始更改列表中的字符串(而不是仅仅改组或从列表中删除它们)将被创建

如果值得的话;您将有2个指向相同对象的列表,因此,如果将来在同一场景中具有可以更改的对象,并且在一个列表中更改了对象,则在另一个列表中也将更改:

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

这就是我们所说的浅表副本

答案 2 :(得分:4)

您的问题来自以下事实:在C#中,我们具有引用类型值类型

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

看看{{1}}。另请参阅Parameter passing by Jon Skeet,它对值和引用类型进行了很好的描述。