- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我试图在我的代码中克隆一个列表,因为我需要将该列表输出到其他代码,但原始引用稍后将被清除。所以我有了使用 Select
扩展方法来创建对相同元素的 IEnumerable
的新引用的想法,例如:
List<int> ogList = new List<int> {1, 2, 3};
IEnumerable<int> enumerable = ogList.Select(s => s);
在执行 ogList.Clear()
之后,我惊讶地发现我的新枚举也是空的。
所以我开始在 LINQPad 中摆弄,发现即使我的 Select
完全返回不同的对象,行为也是相同的。
List<int> ogList = new List<int> {1, 2, 3};
IEnumerable<int> enumerable = ogList.Select(s => 5); // Doesn't return the original int
enumerable.Count().Dump(); // Count is 3
ogList.Clear();
enumerable.Count().Dump(); // Count is 0!
请注意,在 LINQPad 中,Dump()
等同于 Console.WriteLine()
。
现在我首先需要克隆列表的原因可能是设计不当,即使我不想重新考虑设计,我也可以轻松地正确克隆它。但这让我开始思考 Select
扩展方法实际上做了什么。
根据documentation对于选择
:
This method is implemented by using deferred execution. The immediate return value is an object that stores all the information that is required to perform the action. The query represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach in Visual C# or For Each in Visual Basic.
然后我尝试在清除之前添加这段代码:
foreach (int i in enumerable)
{
i.Dump();
}
结果还是一样。
最后,我尝试了最后一件事来弄清楚我的新枚举中的引用是否与旧的相同。我没有清除原始列表,而是:
ogList.Add(4);
然后我打印出我的可枚举(“克隆”的)的内容,希望看到“4”附加到它的末尾。相反,我得到了:
5
5
5
5 // Huh?
现在我别无选择,只能承认我不知道 Select 扩展方法在幕后是如何工作的。怎么回事?
最佳答案
List/List<T>
出于所有意图和目的,花哨的可调整大小的数组。他们拥有并保存值类型的数据,例如您的整数或对内存中引用类型数据的引用,并且他们始终知道他们有多少项。
IEnumerable/IEnumerable<T>
是不同的野兽。他们提供不同的服务/契约(Contract)。一个IEnumerable
是虚构的,不存在的。它可以凭空创建数据,无需物理支持。他们唯一的 promise 是他们有一个名为 GetEnumerator()
的公共(public)方法。返回 IEnumerator/IEnumerator<T>
. IEnumerator
的 promise 制作很简单:当您决定需要时,某些项目可能可用或不可用。这是通过一个简单的方法实现的,即 IEnumerator
界面有:bool MoveNext()
- 当枚举完成时返回 false,如果实际上有一个新项目需要返回则返回 true。您可以通过 IEnumerator
的属性读取数据接口(interface)有,方便叫Current
.
回到您的观察/问题:至于 IEnumerable
在您的示例中,它甚至不会考虑数据,除非您的代码告诉它获取一些数据。
写作时:
List<int> ogList = new List<int> {1, 2, 3};
IEnumerable<int> enumerable = ogList.Select(s => s);
你是说:听这里IEnumerable
,我可能会在将来的某个时候来找你要一些元素。我会告诉你我什么时候需要它们,因为现在坐着不动什么都不做。与 Select(s => s)
您在概念上定义了 int 到 int 的恒等投影。
您编写的选择的一个非常粗略的简化的非现实实现是:
IEnumerable<T> Select(this IEnumerable<int> source, Func<int,T> transformer) something like
{
foreach (var i in source) //create an enumerator for source and starts enumeration
{
yield return transformer(i); //yield here == return an item and wait for orders
}
}
(这解释了为什么你在期待 for 时得到了 5,你的转换是 s => 5)
对于值类型,例如您的情况下的整数:如果要克隆列表,请使用通过 List
实现的枚举结果克隆整个列表或其中的一部分以供将来枚举。 .通过这种方式,您可以创建一个列表,该列表是原始列表的克隆,完全与其原始列表分离:
IEnumerable<int> cloneOfEnumerable = ogList.Select(s => s).ToList();
稍后编辑:当然 ogList.Select(s => s) 等同于 ogList。我将把投影留在这里,因为它在问题中。
您在这里创建的是:来自可枚举结果的列表,通过 IEnumerable<int>
进一步消耗。界面。考虑到我上面所说的关于 IList
的性质对比IEnumerable
,我更愿意写/读:
IList<int> cloneOfEnumerable = ogList.ToList();
警告:小心引用类型。 IList/List
不 promise 保持对象“安全”,它们可以为所有 IList
突变为 null关心。如果您需要关键字:深度克隆。
注意:当心无限或不可倒带的 IEnumerables
关于c# - Linq 的 IEnumerable.Select 是否返回对原始 IEnumerable 的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52450472/
当需要将原始类型转换为字符串时,例如传递给需要字符串的方法时,基本上有两种选择。 以int为例,给出: int i; 我们可以执行以下操作之一: someStringMethod(Integer.to
我有一个位置估计数据库,并且想要计算每月的内核利用率分布。我可以使用 R 中的 adehabitat 包来完成此操作,但我想使用引导数据库中的样本来估计这些值的 95% 置信区间。今天我一直在尝试引导
我希望使用 FTP 编写大型机作业流。为此,我可以通过 FTP 连接到大型机并运行以下命令: QUOTE TYPE E QUOTE SITE FILETYPE=JES PUT myjob.jcl 那么
我是 WPF 的新手。 目前,我正在为名为“LabeledTextbox”的表单元素制作一个用户控件,其中包含一个标签、一个文本框和一个用于错误消息的文本 block 。 当使用代码添加错误消息时,我
我们正在使用 SignalR(原始版本,而不是 Core 版本)并注意到一些无法解释的行为。我们的情况如下: 我们有一个通过 GenericCommand() 方法接受命令的集线器(见下文)。 这些命
使用 requests module 时,有没有办法打印原始 HTTP 请求? 我不只想要标题,我想要请求行、标题和内容打印输出。是否可以看到最终由 HTTP 请求构造的内容? 最佳答案 Since
与直接访问现有本地磁盘或分区的物理磁盘相比,虚拟磁盘为文件存储提供更好的可移植性和效率。VMware有三种不同的磁盘类型:原始磁盘、厚磁盘和精简磁盘,它们各自分配不同的存储空间。 VMware
我有一个用一些颜色着色器等创建的门。 前段时间我拖着门,它问我该怎么办时,我选择了变体。但现在我决定选择创建原始预制件和门颜色,或者着色器变成粉红色。 这是资源中原始预制件和变体的屏幕截图。 粉红色的
我想呈现原始翻译,所以我决定在 Twig 模板中使用“原始”选项。但它不起作用。例子: {{ form_label(form.sfGuardUserProfile.roules_acceptance)
是否可以在sqlite中制作类似的东西? FOREIGN KEY(TypeCode, 'ARawValue', IdServeur) REFERENCES OTHERTABLE(TypeCode, T
这个问题是一个更具体问题的一般版本 asked here .但是,这些答案无法使用。 问题: geoIP数据的原始来源是什么? 许多网站会告诉我我的 IP 在哪里,但它们似乎都在使用来自不到 5 家公
对于Openshift:如何基于Wildfly创建docker镜像? 这是使用的Dockerfile: FROM openshift/wildfly-101-centos7 # Install exa
结果是 127 double middle = 255 / 2 虽然这产生了 127.5 Double middle = 255 / 2 同时这也会产生 127.5 double middle = (
在此处下载带有已编译可执行文件的源代码(大小:161 KB(165,230 字节)):http://www.eyeClaxton.com/download/delphi/ColorSwap.zip 原
以下几行是我需要在 lua 中使用的任意正则表达式。 ['\";=] !^(?:(?:[a-z]{3,10}\s+(?:\w{3,7}?://[\w\-\./]*(?::\d+)?)?/[^?#]*(
这个问题是一个更具体问题的一般版本 asked here .但是,这些答案无法使用。 问题: geoIP数据的原始来源是什么? 许多网站会告诉我我的 IP 在哪里,但它们似乎都在使用来自不到 5 家公
我正在使用GoLang做服务器api,试图管理和回答所发出的请求。使用net/http和github.com/gorilla/mux。 收到请求时,我使用以下结构创建响应: type Response
tl; dr:我认为我的 static_vector 有未定义的行为,但我找不到它。 这个问题是在 Microsoft Visual C++ 17 上。我有这个简单且未完成的 static_vecto
我试图找到原始 Awk (a/k/a One True Awk) 源代码的“历史”版本。我找到了 Kernighan's occasionally-updated site ,它似乎总是链接到最新版本
我在 python 中使用原始 IPv6 套接字时遇到一些问题。我通过以下方式连接: if self._socket != None: # Close out old sock
我是一名优秀的程序员,十分优秀!