2011-05-17 1 views
4

J'essaie de tirer parti des itérateurs en C# pour nettoyer certaines requêtes spatiales sur les objets dans un jeu que je fais.itération sur une collection personnalisée d'objets avec rendement et foreach sans boxe/unboxing

Voici ce que je fais actuellement:

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; 
     } 
    } 

Cela fonctionne très bien, sauf que je pense qu'il ya de la boxe/unboxing passe. Le CLRProfiler semble vérifier cela car je vois des allocations se produire dans ma méthode Explode. J'aimerais beaucoup éviter les allocations après le démarrage, donc je ne déclenche pas le garbage collector au milieu d'un niveau ou quelque chose. Est-il possible de garder cette syntaxe en évitant toute allocation? Peut-être en mettant en œuvre mes propres itérateurs ou quelque chose?

Répondre

0

Les allocations dans votre méthode Explode sont dues au fonctionnement interne de l'itérateur lui-même, et non à cause de la boxe.

Chaque bloc itérateur est mis en œuvre par le compilateur en utilisant une classe de référence pour maintenir l'état qui est utilisé au cours de la itérer sur IEnumerable, dans votre cas foreach. Normalement, l'allocation de cette classe n'est pas considérée comme un problème, car l'itérateur itère sur une grande collection ou le client qui itère effectue un travail substantiel qui lui est propre ou une allocation qui dépasse l'allocation des itérateurs.

Mais si votre collection est petit (comme le vôtre est), et le foreach est très rapide et n'a pas de sa propre allocation, tout ce qui sera laissé est l'attribution de la classe d'état iterator.

Pour résoudre ce problème de performance, vous pouvez simplement réorganiser votre code pour utiliser for au lieu de foreach whereever le profileur vous dit beaucoup de mémoire est allouée dans un bloc itérateur. C'est généralement un changement modeste et l'augmentation de la performance si elle est mesurable en vaut la peine.

2

Votre code ne fait pas de la boxe.

boxe ne se produit que lorsque vous mettez un struct dans un champ object.
Étant donné que votre code est entièrement typé et qu'il n'a aucun champ object, il n'est pas encadré.

Appel d'une méthode iterator va créer une nouvelle allocation objet iterator (qui implements both IEnumerable<T> and IEnumerator<T>), mais ne devrait pas donner lieu à d'autres (derrière les coulisses).

+0

Je vois. Je pensais que mon ObjectInfo était peut-être bourré dans un objet par l'itérateur. Est-ce que je peux faire mon propre itérateur qui est aussi un struct? Je vais regarder par-dessus le lien que vous avez fourni et voir si je peux le comprendre. – hahanoob

+0

Il semble qu'il ne soit pas possible d'utiliser le rendement de rendement sans affecter un objet de classe dans les coulisses. C'est malheureux. – hahanoob

+0

@haha: Comment pouvez-vous retourner un 'IEnumerable ' sans créer d'objet? – SLaks

Questions connexes