Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.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
是否列出<;T>;在foreach中的C#中创建垃圾_C#_Performance_Generics_Garbage Collection - Fatal编程技术网

是否列出<;T>;在foreach中的C#中创建垃圾

是否列出<;T>;在foreach中的C#中创建垃圾,c#,performance,generics,garbage-collection,C#,Performance,Generics,Garbage Collection,如果我错了,请纠正我,但在执行foreach时,IEnumerable会创建垃圾,无论T是什么。但我想知道你是否有一个列表,其中T是实体。然后假设列表中有一个派生类,如Entity2D。它必须为每个派生类创建一个新的枚举数吗?所以制造垃圾 还有一个接口,比如说,IEntity作为创建垃圾的工具?List的GetEnumerator方法实际上是非常有效的 当您在列表的元素中循环时,它调用GetEnumerator。这反过来会生成一个内部结构,其中包含对原始列表的引用、索引和版本ID,以跟踪列表中的

如果我错了,请纠正我,但在执行foreach时,
IEnumerable
会创建垃圾,无论T是什么。但我想知道你是否有一个
列表
,其中T是实体。然后假设列表中有一个派生类,如Entity2D。它必须为每个派生类创建一个新的枚举数吗?所以制造垃圾

还有一个接口,比如说,
IEntity
作为创建垃圾的工具?

List
的GetEnumerator方法实际上是非常有效的

当您在
列表的元素中循环时,它调用GetEnumerator。这反过来会生成一个内部
结构
,其中包含对原始列表的引用、索引和版本ID,以跟踪列表中的更改

然而,由于正在使用结构,它实际上并没有创建GC将要处理的“垃圾”


< >“为每个派生类创建新枚举器”.NET泛型与C++模板不同。在.NET中,
列表
类(及其内部的
枚举器
结构)定义一次,可用于任何T。使用时,需要该特定类型的T的泛型类型,但这只是新创建的类型的类型信息,通常非常小。这与C++模板不同,例如,每个类型都是在编译时创建的,并且“内置”到可执行文件。
在.NET中,可执行文件指定
列表
,而不是
列表
列表
,等等的定义。

无论它是
列表
列表
,还是
列表
GetEnumerator
,都将每个foreach调用一次。此外,例如
List
是否包含
Entity2D
的实例并不重要。
IEnumerable
GetEnumerator
实现可能会创建要收集的引用对象。正如Reed所指出的,MS.NET中的
List
通过只使用值类型来避免这种情况。

我想您可能会感兴趣,这解释了为什么List(T)不会创建“垃圾”,而不是Collection(T):

现在,棘手的部分来了。谣传System.Collections.Generic中的许多类型在使用foreach时不会分配枚举数。例如,List的GetEnumerator返回一个结构,它将位于堆栈上。如果您不相信我,请使用.NET Reflector查找您自己。为了向自己证明列表上的foreach不会导致任何堆分配,我将实体更改为列表,执行了完全相同的foreach循环,并运行了探查器。没有统计员

[……]

然而,以上肯定有一个警告。列表上的Foreach循环仍然会生成垃圾。[将列表强制转换为IEnumerable]即使我们仍在对列表执行foreach,但当列表强制转换为接口时,必须将值类型枚举数装箱并放置在堆上

一个有趣的注意事项:正如所示,该类型实际上是一个
结构。这既是好的,也是可怕的

在某种意义上说,在
列表上调用
foreach
实际上不会创建垃圾,因为没有为垃圾收集器分配新的引用类型对象

从某种意义上说,
GetEnumerator
的返回值突然变成了一种值类型,几乎违背了每个.NET开发人员的直觉,这是非常可怕的(通常预期
GetEnumerator
将返回一个非描述的
IEnumerator
,因为这是
IEnumerable
合同所保证的;
List
通过显式实现
IEnumerable.GetEnumerator
并公开
IEn的更具体实现来解决这个问题umerator
恰好是一种值类型)

因此,任何代码,例如,将
List.Enumerator
传递给一个单独的方法,该方法反过来调用该Enumerator对象上的
MoveNext
,都会面临无限循环的潜在问题。如下所示:

int CountListMembers<T>(List<T> list)
{
    using (var e = list.GetEnumerator())
    {
        int count = 0;
        while (IncrementEnumerator(e, ref count)) { }

        return count;
    }
}

bool IncrementEnumerator<T>(IEnumerator<T> enumerator, ref int count)
{
    if (enumerator.MoveNext())
    {
        ++count;
        return true;
    }

    return false;
}
int countlist成员(列表)
{
使用(var e=list.GetEnumerator())
{
整数计数=0;
while(递增枚举数(e,ref count)){
返回计数;
}
}
布尔递增枚举数(IEnumerator枚举数,ref int count)
{
if(枚举数.MoveNext())
{
++计数;
返回true;
}
返回false;
}
上面的代码非常愚蠢;它只是一个简单的例子,其中
List.GetEnumerator
的返回值可能导致高度不直观(并且可能是灾难性的)行为


但正如我所说的,它仍然有点好,因为它不会产生垃圾;

列表
显式实现
IEnumerator
,因此对类型为
列表的变量调用
GetEnumerator
将导致它返回一个
列表。Enumerator
,它具有值类型语义,然而,对包含对
列表的引用的
IEnumerator
类型的变量调用它将导致它返回一个
IEnumerator
类型的值,该类型的值将具有引用语义。

你是什么意思?迭代IEnumerable不会产生“垃圾”。哈哈,你抽了什么?还定义了“垃圾”。foreach从一开始就为我提供了一个列表。@driis它创建了IEnumerator的新实例。这是可以考虑的garbage@Andrey:虽然列表生成的IEnumerator是一个结构,但它不会增加任何GC压力,因为它保存在堆栈上(当然,除非您自己将其粘贴到类中,但这会非常非常奇怪…@Reed:不会那么奇怪。例如,看看+1。它们也不同于Java的泛型,后者纯粹是一种编译时特性(所有出现的
T
类型都是