两个c#列表都被修改

时间:2016-03-11 12:26:08

标签: c# data-structures

我的两个列表都在修改,我正试图避免这种行为......

这里有什么问题?

我有一个'大'列表,我想删除itemsToRemoveList中存在的所有项目,但不修改原始列表。

我已经简化了示例代码..

List<string> aList = new List<string>(){"My","name","is", "jeff"}; // cached full list

List<string> bList = aList; // initial copy

List<string> itemsToRemoveList = new List<string>(){"jeff"};

bList.RemoveAll(itemsToRemoveList.Contains); // remove only from copy

foreach (string s in aList)
{
    Console.Write(s + " "); // expect "my name is jeff"
}
Console.WriteLine();
foreach (string s in bList)
{
    Console.Write(s + " "); // expect "my name is"
}
// however this modifies both collections. 

        Console.ReadLine();

6 个答案:

答案 0 :(得分:7)

当你这样做时

List<string> bList = aList;

这不是创建新列表。它只是将您的bList变量设置为与aList指向同一列表的引用。制作副本的方法是实际创建一个新列表。

List<string> bList = new List<string>(aList);

但如果您还想过滤值,最好使用Linq。

List<string> aList = new List<string>(){"My","name","is", "jeff"}; 
List<string> itemsToRemoveList = new List<string>(){"jeff"};
List<string> bList = aList.Where(a => !itemsToRemoveList.Contains(a)).ToList(); 

foreach (string s in aList)
{
    Console.Write(s + " "); 
}
Console.WriteLine();
foreach (string s in bList)
{
    Console.Write(s + " "); 
}

答案 1 :(得分:0)

您的问题是您只是引用同一个对象。 要避免此行为,您必须像这样初始化列表B:

List<string> bList = new List<string>(aList);

答案 2 :(得分:0)

请记住.Net中的对象是引用类型,当您将一个引用类型分配给另一个时,实际上是指定了一个指向原始对象内存中位置的指针。

List<string> aList = new List<string>(){"My","name","is", "jeff"}; // cached full list
List<string> bList = aList; // <- NOT a copy, this is assigning the same object

你提到你有一个相当大的清单。如果你的意思是数千或更少,那么juharr的答案很棒。如果列表中有数百万个项目,您可能需要重新考虑首先填充该列表的方式,并可能修改数据库查询。

答案 3 :(得分:0)

您可以使用LINQ以外:

List<int> a = new List<int>{ 1, 2 };
List<int> b = new List<int> { 2 };
var c = a.Except(b);

答案 4 :(得分:0)

您收到此行为是因为您只是引用原始列表。您的第二个列表只是指向与原始内存相同的内存地址。您需要添加以下内容:

    List<string> aList = new List<string>() { "My", "name", "is", "jeff" }; // cached full list

    List<string> bList = new List<string>();

    foreach(var item in aList)
    {
        bList.add(item);
    }

    List<string> itemsToRemoveList = new List<string>() { "jeff" };

    bList.RemoveAll(itemsToRemoveList.Contains); // remove only from copy

    foreach (string s in aList)
    {
        Console.Write(s + " "); // expect "my name is jeff"
    }
        Console.WriteLine();
    foreach (string s in bList)
    {
        Console.Write(s + " "); // expect "my name is"
    }
    // however this modifies both collections. 

    Console.ReadLine();

这将创建原始列表的真实副本,并完成您正在寻找的行为。

答案 5 :(得分:0)

在您的代码中:

List<string> bList = aList;

不复制列表,而是复制对列表的引用。这就是为什么当您更改一个列表时,更改会反映在另一个列表中,因为它们实际上是相同的列表。

要创建新列表,您需要使用:

List<string> bList = new List<string>(aList);

有关详细信息,请参阅List参考。

另外,请确保您了解C#中值和引用类型之间的区别。分配引用类型时,只是复制引用,而在分配值类型时,则复制数据。只有原始类型,结构和枚举是C#中的值类型,其他一切都是引用类型。在您的示例中,您正在处理作为引用类型的列表对象,但您希望它的行为类似于值类型。阅读更多here