在c#中,是否有一种默认的方式来创建一个添加了项的新列表,而不修改原始列表?

本文关键字:列表 新列表 添加 原始 修改 一个 是否 一种 创建 方式 默认 | 更新日期: 2023-09-27 18:18:24

基本上是一个附加函数,如果我给出一个列表和一个项目,它返回一个添加了该项目的全新列表。我不是在问如何做到这一点,我想知道是否已经有一个有效的方法来做到这一点内置到。net源代码。显然我可以这样做;

List<string> newList = new List<string>();
newList.AddRange(oldList);
newList.Add(newElem);

但是有更好的方法吗?

在c#中,是否有一种默认的方式来创建一个添加了项的新列表,而不修改原始列表?

是的,不可变集合。https://dotnetcodr.com/2015/09/23/using-immutable-collections-for-thread-safe-read-only-operations-in-net/

https://blogs.msdn.microsoft.com/dotnet/2013/09/25/immutable-collections-ready-for-prime-time/

可通过nuget包"System.Collections. "获得。不可改变的"。

从站点:

什么是不可变集合?随着时间的推移,。net框架已经增加了许多使并发编程更容易的特性。这是从引入线程池开始的,还有更多强大的基于任务的模型和任务并行库(TPL),并且通过添加异步和等待语言关键字。同时创建和运行是比以往任何时候都容易的是,一个基本问题仍然存在:可变共享状态。从多个线程读取通常非常困难很简单,但一旦需要更新状态,就会变得困难得多,特别是在需要锁定的设计中。锁定的替代方案就是利用不可变状态。不可变数据结构是保证永远不会改变,因此可以在两者之间自由传递不同的线索,不用担心踩到别人的脚趾。

正如其他人回答的那样,没有不可变集合也可以做到这一点。如果你是唯一一个参与项目的人,或者如果你确信自己可以控制源代码,那么这可能会更好。但是错误是很容易犯的,特别是当你的列表有很多修改的时候。使用不可变集合,您不必担心,或者更少担心这类错误。

试试这个:

List<string> newList = new List<string>(oldList) { newElem };

是的,使用linq.

var list = new []{1, 3, 4}.Concat(new []{6}).ToList() // list now contains 1,3,4,6

还可以为Concat定义一个接受单个元素的重载,这样就不必创建只有一个元素的列表了。

为了避免调整大小(涉及创建新的内部数组和数组复制操作),我将通过指定其新的初始容量来创建新列表,但其他方面仍使用您的方法:

List<string> newList = new List<string>(oldList.Count + 1);
newList.AddRange(oldList);
newList.Add(newElem);

一个完全不同的方法是从函数式语言中借用一个概念,在函数式语言中使用链表。不是创建列表的副本并添加一个项,而是在列表前面添加新项,并将对第一个项的引用作为对列表其余部分的引用返回。该列表只能从这一项一直枚举到最后。这是线程安全的,因为线程永远不会看到新添加的项。