使用收益和foreach迭代自定义对象集合,而无需装箱/取消装箱
本文关键字:取消装箱 集合 收益 foreach 迭代 对象 自定义 | 更新日期: 2023-09-27 17:56:43
我正在尝试利用 C# 中的迭代器来清理我正在制作的游戏中对对象的一些空间查询。
这是我目前正在做的事情:
public struct ObjectInfo
{
public int x, y;
public int Type;
public int hp;
}
public static IEnumerable<ObjectInfo> NearbyObjects(int x, int y, int distance)
{
// Not actually what I'm doing, but for simplicity...
for (int i = 0; i < 10; ++ i)
{
yield return new ObjectInfo();
}
}
public static void Explode()
{
foreach (ObjectInfo o in NearbyObjects(0, 0, 1))
{
o.hp = 0;
}
}
这很好用,除了我认为有一些装箱/拆箱正在进行。CLRProfiler 似乎验证了这一点,因为我看到我的 Explode 方法中发生了分配。我非常想在启动后避免任何分配,所以我不会在关卡或其他东西中间触发垃圾收集器。有没有办法在避免任何分配的同时保留此语法?也许通过实现我自己的迭代器或其他东西?
您的代码不执行任何装箱操作。
只有当你把struct
放进object
场时,才会发生拳击。
由于您的代码是完全强类型的,并且没有任何object
字段,因此它不会装箱。
调用迭代器方法将创建一个新的迭代器对象(实现IEnumerable<T>
和IEnumerator<T>
),但不会导致任何其他(后台)分配。
装箱/拆箱将发生在结构体中。
请参阅此处: http://msdn.microsoft.com/en-us/library/aa664476(v=vs.71).aspx
同样在这里:将结构转换为通用接口时是否有装箱/拆箱?
Explode
方法中的分配是由于迭代器本身的内部工作,而不是由于装箱。
每个迭代器块都由编译器使用引用类来实现,以维护在迭代IEnumerable
过程中使用的状态,在您使用foreach
的情况下。 通常,此类的分配不会被视为问题,因为迭代器迭代大型集合,或者正在迭代的客户端正在执行自己的大量工作或分配,这些工作使迭代器分配不堪重负。
但是,如果你的集合很小(就像你的一样),并且foreach
非常快并且没有自己的分配,那么剩下的就是迭代器状态类的分配。
要解决此性能问题,您可以简单地重新组织代码以使用for
而不是foreach
探查器告诉您在迭代器块中分配了大量内存。 这通常是一个适度的变化,如果可衡量,性能提升是值得的。