c# – 使用yield和foreach迭代自定义的对象集合,无需装箱/取消装箱

我正在尝试利用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方法中发生了分配.我非常想在启动后避免任何分配,所以我不会在一个级别或类似的东西中触发垃圾收集器.有什么方法可以保留这种语法,同时避免任何分配?也许通过实现我自己的迭代器或其他东西?

最佳答案
您的Explode方法中的分配是由于迭代器本身的内部工作原因,而不是由于装箱.

每个迭代器块都由编译器使用引用类来实现,以维护在使用foreach的情况下迭代IEnumerable的过程中使用的状态.通常,这个类的分配不会被注意到是一个问题,因为迭代器会迭代一个大型集合,或者正在迭代的客户端正在进行自己的实质性工作或分配的操作,这些工作会超过迭代器的分配.

但是如果你的集合很小(就像你的那样),并且foreach非常快并且没有自己的分配,那么剩下的就是迭代器状态类的分配.

要解决此性能问题,您可以简单地重新组织代码以用于代替foreach,无论分析器告诉您在迭代器块中分配了大量内存.它通常是一个适度的变化,如果可衡量的话,性能提升是值得的.

转载注明原文:c# – 使用yield和foreach迭代自定义的对象集合,无需装箱/取消装箱 - 代码日志