【发布时间】:2020-10-01 22:33:04
【问题描述】:
给定以下代码:
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
//Init data
char[] chars = new char[10];
FillData(chars);
// Write the initial data
PrintContents("Initial data:", chars);
//Take some data:
IEnumerable<char> acc = chars.Take(3);
//View data
PrintContents("Enum:", acc);
//Edit data
chars[0] = 'z';
chars[1] = 'z';
chars[2] = 'z';
//View data again
PrintContents("Enum after modifing source:", acc);
//Restart data
chars = new char[5];
FillData(chars);
//View data when source is replaced
PrintContents("Enum after new source:", acc);
}
//Gets a ref
private static void FillData(char[] data)
{
for(int i = 0; i < data.Length; i++)
{
data[i] = (char)('a' + i);
}
}
private static void PrintContents(string what, IEnumerable<char> src)
{
System.Console.WriteLine(what);
string s = "";
foreach(char ch in src)
{
s += ch;
}
if(s.Length > 0)
{
System.Console.WriteLine(s);
}
}
}
我得到这个输出:
Initial data:
abcdefghij
Enum:
abc
Enum after modifing source:
zzz
Enum after new source:
zzz
我知道延迟执行,但这是预期的行为吗? 这意味着我应该在不创建新集合的情况下重用 IEnumerable 或在 IEnumerable 上使用的任何数据,因为我可能会更改程序的结果。
这意味着 IEnumerable 也将持有对数据源的引用,即使它们也未被可见代码使用,并且在 IEnumerable 本身被收集之前不会被垃圾收集。
我在最近的一个项目中经常使用 IEnumerable,但我看到的越多,我就越不喜欢它们。不要误会我的意思,Linq 做得很好,但我希望它有时返回相同类型的源代码。
【问题讨论】:
-
作为一个小演示,您可以绕过
IEnumerable持有它自己的引用,如下所示:dotnetfiddle.net/VcI2ai。尽管请记住,在迭代期间它仍然具有引用。当然,如果有人为此调用ToList()之类的东西,然后继续使用List,对源的任何更改都不会再反映在枚举中
标签: c# collections ienumerable consistency data-consistency