如何在不更改原始列表的情况下更改新列表?
我有一个列表,从操作中填入一些数据,我将其存储在内存缓存中。 现在我想要另一个列表,其中包含基于某些条件的列表中的一些子数据。
从下面的代码中可以看出,我正在对目标列表进行一些操作。 问题是我对目标列表所做的任何更改也都在对mainList进行。 我认为它因为参考是相同的或什么的。
我只需要在目标列表上的操作不会影响主列表中的数据。
List target = mainList; SomeOperationFunction(target); void List SomeOperationFunction(List target) { target.removeat(3); return target; }
您需要在方法中克隆列表,因为List
是一个类,所以它是引用类型并通过引用传递。
例如:
List- SomeOperationFunction(List
- target) { List
- tmp = target.ToList(); tmp.RemoveAt(3); return tmp; }
要么
List- SomeOperationFunction(List
- target) { List
- tmp = new List
- (target); tmp.RemoveAt(3); return tmp; }
要么
List- SomeOperationFunction(List
- target) { List
- tmp = new List
- (); tmp.AddRange(target); tmp.RemoveAt(3); return tmp; }
您需要复制列表,以便对副本的更改不会影响原件。 最简单的方法是在System.Linq
使用ToList
扩展方法。
var newList = SomeOperationFunction(target.ToList());
首先构建一个新列表并对其进行操作,因为List是一个引用类型,即当你在函数中传递它时,你不仅要传递值而是传递实际对象本身。
如果只是将target
指定给mainList
,则两个变量都指向同一个对象,因此您需要创建一个新的List:
List- target = new List
- (mainList);
void List
没有意义,因为要么返回任何内容( void
),要么返回List
。 因此,要么从方法中删除return语句,要么返回一个新的List
。 在后一种情况下,我会将其重写为:
List- target = SomeOperationFunction(mainList); List
- SomeOperationFunction(List
- target) { var newList = new List
- (target); newList.RemoveAt(3); return newList; }
您的目标变量是引用类型。 这意味着您对它所做的任何事情都会反映在您传递给它的列表中。
若要不这样做,您将需要在方法中创建新列表,将target
内容复制到该列表,然后在新列表上执行删除操作。
关于参考和价值类型
即使您创建了一个新列表,对新列表中项目的引用仍将指向旧列表中的项目,因此如果我需要一个包含新引用的新列表,我希望使用此扩展方法…
public static IEnumerable Clone (this IEnumerable target) where T : ICloneable { If (target.IsNull()) throw new ArgumentException(); List retVal = new List (); foreach (T currentItem in target) retVal.Add((T)(currentItem.Clone())); return retVal.AsEnumerable(); }
您正在查看正在修改的原始列表,因为默认情况下,任何非基本对象都是通过引用传递的(它实际上是按值传递,值是引用,但这是另一回事)。
你需要做的是克隆对象。 这个问题将帮助您使用一些代码克隆C#中的List: 如何在C#中克隆通用列表?
而不是将mainList分配给目标,我会这样做: target.AddRange(mainList);
然后,您将获得项目的副本,而不是对列表的引用。
只需确保使用通过复制源列表的元素创建的列表初始化新列表。
List
应该是List
您需要复制一份列表,因为在原始代码中您正在做的只是传递,正如您所怀疑的那样,一个引用(某人称之为指针)。
您可以在新列表上调用构造函数,将原始列表作为参数传递:
List- SomeOperationFunction(List
- target) { List
- result = new List
- (target); result.removeat(3); return result; }
或者创建一个MemberWiseClone :
List- SomeOperationFunction(List
- target) { List
- result = target.MemberWiseClone(); result.removeat(3); return result; }
此外,您没有在任何地方存储SomeOperationFunction
的返回值,因此您可能也想修改该部分(您将该方法声明为void
,它不应返回任何内容,但在其中您将返回一个对象)。 你应该这样调用方法:
List- target = SomeOperationFunction(mainList);
注意:列表的元素不会被复制(只复制它们的引用),因此修改元素的内部状态将影响两个列表。
由于List
是引用类型,因此传递给函数的是对原始列表的引用。
有关如何在C#中传递参数的详细信息,请参阅此MSDN文章 。
为了达到你想要的效果,你应该在SomeOperationFunction
创建一个列表的副本,然后返回它。 一个简单的例子:
void List- SomeOperationFunction(List
- target) { var newList = new List
- (target); newList.RemoveAt(3); return newList; // return copy of list }
正如Olivier Jacot-Descombes在对另一个答案的评论中指出的那样,重要的是要记住这一点
[…]如果项目是引用类型,列表仍然保留对相同项目的引用。 因此,对项目本身的更改仍会影响两个列表中的项目。