Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在不更改原始列表的情况下更改新列表?_C# - Fatal编程技术网

C# 如何在不更改原始列表的情况下更改新列表?

C# 如何在不更改原始列表的情况下更改新列表?,c#,C#,我有一个列表,其中填充了一个操作中的一些数据,并将其存储在内存缓存中。现在我想要另一个列表,它包含列表中基于某些条件的一些子数据 从下面的代码中可以看出,我正在对目标列表执行一些操作。问题是,我对目标列表所做的任何更改也会对主列表进行更改。我想这是因为它的引用是一样的或者什么的 我所需要的只是对目标列表的操作不会影响主列表中的数据 List<Item> target = mainList; SomeOperationFunction(target); void List<I

我有一个列表,其中填充了一个操作中的一些数据,并将其存储在内存缓存中。现在我想要另一个列表,它包含列表中基于某些条件的一些子数据

从下面的代码中可以看出,我正在对目标列表执行一些操作。问题是,我对目标列表所做的任何更改也会对主列表进行更改。我想这是因为它的引用是一样的或者什么的

我所需要的只是对目标列表的操作不会影响主列表中的数据

List<Item> target = mainList;
SomeOperationFunction(target);

 void List<Item> SomeOperationFunction(List<Item> target)
{
  target.removeat(3);
  return target;
}
List target=mainList;
某些操作功能(目标);
void List SomeOperationFunction(列表目标)
{
目标。移除(3);
回报目标;
}

您的目标变量是引用类型。这意味着你对它所做的任何事情都会反映在你传递给它的列表中

为此,您需要在方法中创建一个新列表,将
target
内容复制到其中,然后对新列表执行remove at操作


您需要在方法中克隆列表,因为
list
是一个类,所以它是引用类型,并通过引用传递

例如:

List<Item> SomeOperationFunction(List<Item> target)
{
  List<Item> tmp = target.ToList();
  tmp.RemoveAt(3);
  return tmp;
}
列出一些操作函数(列出目标)
{
List tmp=target.ToList();
tmp.RemoveAt(3);
返回tmp;
}

列出一些操作函数(列出目标)
{
列表tmp=新列表(目标);
tmp.RemoveAt(3);
返回tmp;
}

列出一些操作函数(列出目标)
{
List tmp=新列表();
tmp.AddRange(目标);
tmp.RemoveAt(3);
返回tmp;
}

首先构建一个新列表并对其进行操作,因为列表是一种引用类型,即当您在函数中传递它时,您不仅传递值,而且传递实际对象本身

如果仅将
target
分配给
mainList
,则两个变量都指向同一个对象,因此需要创建一个新列表:

List<Item> target = new List<Item>(mainList);

您需要制作列表的副本,以便对副本所做的更改不会影响原始列表。最简单的方法是在
System.Linq
中使用
ToList
扩展方法

var newList = SomeOperationFunction(target.ToList());

您看到的是原始列表被修改,因为默认情况下,任何非基本体对象都是通过引用传递的(它实际上是通过值传递的,值就是引用,但这是另一回事)


您需要做的是克隆对象。这个问题将帮助您使用一些代码来克隆C#::

中的列表,因为
列表
是一种引用类型,所以传递给函数的是对原始列表的引用

有关如何在C#中传递参数的更多信息,请参见此

为了实现您想要的功能,您应该在
SomeOperationFunction
中创建列表的副本,并将其返回。一个简单的例子:

void List<Item> SomeOperationFunction(List<Item> target)
{
  var newList = new List<Item>(target);
  newList.RemoveAt(3);
  return newList; // return copy of list
}
void List SomeOperationFunction(列表目标)
{
var newList=新列表(目标);
新列表。删除(3);
return newList;//返回列表的副本
}
正如Olivier Jacot Descombes在对另一个答案的评论中指出的,重要的是要记住

[…]如果出现以下情况,列表仍然包含对相同项目的引用: 这些项目属于引用类型。因此,对项目本身的更改 仍将影响两个列表中的项目


我不会将mainList分配给目标,而是执行:
target.AddRange(mainList)


然后,您将拥有项目的副本,而不是列表的引用。

只需确保使用通过复制源列表的元素创建的列表初始化新列表即可


List target=mainList应该是<代码>列表目标=新列表(主列表)

您需要制作列表的副本,因为在您的原始代码中,您所做的只是传递一个引用,正如您正确地怀疑的那样(有人会称之为指针)

您可以调用新列表上的构造函数,将原始列表作为参数传递:

List<Item> SomeOperationFunction(List<Item> target)
{
    List<Item> result = new List<Item>(target);
    result.removeat(3);
    return result;
}

注意:不会复制列表中的元素(只复制它们的引用),因此修改元素的内部状态将影响两个列表。

即使创建新列表,对新列表中项目的引用仍将指向旧列表中的项目,所以如果我需要一个包含新引用的新列表,我喜欢使用这个扩展方法

public static IEnumerable<T> Clone<T>(this IEnumerable<T> target) where T : ICloneable
{
    If (target.IsNull())
        throw new ArgumentException();

    List<T> retVal = new List<T>();

    foreach (T currentItem in target)
        retVal.Add((T)(currentItem.Clone()));

    return retVal.AsEnumerable();
}
公共静态IEnumerable克隆(此IEnumerable目标),其中T:ICloneable
{
If(target.IsNull())
抛出新ArgumentException();
List retVal=新列表();
foreach(目标中的T currentItem)
retVal.Add((T)(currentItem.Clone());
返回retVal.AsEnumerable();
}

我尝试了上面的许多答案。在我测试的所有列表中,对新列表的更新会修改原始列表。这对我来说很有用

var newList = JsonConvert.DeserializeObject<List<object>>(JsonConvert.SerializeObject(originalList));
return newlist.RemoveAt(3);
var newList=JsonConvert.DeserializeObject(JsonConvert.SerializeObject(originalList));
返回newlist.RemoveAt(3);

您是说两个列表中的对象都被修改了吗?也就是说,您是否需要克隆()/创建它们的副本,而不是处理相同的实例?选择在这里不起任何作用,您只需要
ToList
。第三个示例完全错误。
tmp
var用于填充自身。然后您仍然从
target
中删除元素,而不是从
tmp'
@PLB
ToList
中删除元素,从而创建一个新列表。它接受一个
IEnumerable
作为输入。它的内容基本上就是
返回新列表(source)
@PLB我相信包含的所有LINQ表达式,
ToList()
都会返回数据的新副本,以便操作可以假定原始数据是不可变的。@JesseWebb它必须返回一个新列表,因为源序列不太可能是列表,所以它需要为几乎所有其他情况创建一个新列表。这将是令人困惑的,容易出错的,一个
List<Item> SomeOperationFunction(List<Item> target)
{
    List<Item> result = new List<Item>(target);
    result.removeat(3);
    return result;
}
List<Item> SomeOperationFunction(List<Item> target)
{
    List<Item> result = target.MemberWiseClone();
    result.removeat(3);
    return result;
}
List<Item> target = SomeOperationFunction(mainList);
public static IEnumerable<T> Clone<T>(this IEnumerable<T> target) where T : ICloneable
{
    If (target.IsNull())
        throw new ArgumentException();

    List<T> retVal = new List<T>();

    foreach (T currentItem in target)
        retVal.Add((T)(currentItem.Clone()));

    return retVal.AsEnumerable();
}
var newList = JsonConvert.DeserializeObject<List<object>>(JsonConvert.SerializeObject(originalList));
return newlist.RemoveAt(3);