Итерация по пользовательской коллекции объектов с yield и foreach без упаковки / распаковки - PullRequest
4 голосов
/ 17 мая 2011

Я пытаюсь воспользоваться итераторами в 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. Я бы очень хотел избежать каких-либо выделений после запуска, чтобы не запускать сборщик мусора в середине уровня или что-то в этом роде. Есть ли способ сохранить этот синтаксис, избегая какого-либо выделения? Может быть, путем реализации моих собственных итераторов или что-то?

Ответы [ 3 ]

2 голосов
/ 17 мая 2011

Ваш код не выполняет никакой блокировки.

Бокс происходит только тогда, когда вы вводите struct в поле object.
Поскольку ваш код полностью строго типизирован и не имеетлюбые поля object, это не поле.

Вызов метода итератора создаст новый объект итератора (который реализует как IEnumerable<T>, так и IEnumerator<T>), но не долженприводить к любым другим (закулисным) выделениям.

1 голос
/ 17 мая 2011

Бокс / распаковка будет происходить со структурами.

Смотрите здесь: http://msdn.microsoft.com/en-us/library/aa664476(v=vs.71).aspx

Также здесь: Есть ли Boxing / Unboxing при приведении структуры в общий интерфейс?

0 голосов
/ 17 мая 2011

Выделения в вашем методе Explode происходят из-за внутренней работы самого итератора, а не из-за упаковки.

Каждый блок итератора реализуется компилятором с использованием ссылочного класса для поддержания состояния, котороеиспользуется в ходе итерации по IEnumerable, в вашем случае с foreach.Обычно выделение этого класса не замечается как проблема, потому что итератор выполняет итерации по большой коллекции, или клиент, выполняющий итерацию, выполняет существенную собственную работу или распределение, которое перебивает распределение итераторов.

Но если вашколлекция небольшая (как у вас), и foreach очень быстрый и не имеет собственных выделений, все, что останется, - это выделение класса состояния итератора.

Чтобы решить эту проблему с производительностью, вы можете просто реорганизовать свой код, чтобы использовать for вместо foreach, когда бы профилировщик сообщал вам, что в блоке итератора выделяется много памяти.Обычно это скромное изменение, и повышение производительности, если его можно измерить, того стоит.

...