I am trying to make a flexible particle system for my XNA game, and I've got these interfaces:
public interface IParticle : IUpdateable
{
bool Alive { get; }
float Percent { get; }
}
public interface IParticleEffect<T>
where T : IParticle
{
void Apply(GameTime time, ref T particle);
}
public interface IParticleEmitter<T> : IUpdateable
where T : IParticle
{
}
public interface IParticleRenderer<T> : IDrawable
where T : IParticle
{
}
The idea behind this system is that the client code only needs to derive from IParticle
, then make a compatible subclass from IParticleEmitter
and IParticleRenderer
, and everything else just automagically works behind the scenes. (I'm actually in the middle of writing everything at the moment, but the latter two would have an abstract base class available.)
Anyways, some particle systems like to use mutable structs for optimization purposes, and that's perfectly reasonable. My system only provides the skeleton, and if the client decides that "Hey, structs are the way to go!", then my system should support whatever the client code throws at it. This is why my IParticleEffect.Apply()
method takes a particle by ref -- it's cheaper to pass a struct by reference than it is to copy it.
Unfortunately, it breaks when collections are involved, because the foreach iterator doesn't play nicely with objects passed by ref or out. Eric Lippert explains why here.
So, now I have a design decision to make:
- Completely disregard structs, and change my constraint to
where T: class, IParticle
. This potentially hurts future optimizations, but makes it much easier to work with collections. - Change anything that uses
ICollection<T>
orIEnumerable<T>
toIList<T>
so I can manually poll it via an indexer. This makes it potentially more powerful, but at the cost of using a deeper interface (list) to store my objects. - Something else
I hope this question isn't too "it depends", but I am curious as to what strategies I can apply here to make it work the way I want.
EDIT: I realized that I could also include a local variable such as:
foreach (var particle in SomeParticleCollection)
{
var p = particle;
SomeEffect.Apply(ref p);
}
However, p
would still have the net effect of copying it, which is also not ideal.