I'm making a simple particle system in C#/XNA, and since there would potentially be a high volume of method calls every second, I wanted to make sure I understood exactly how everything works.
I have a Particle and Emitter class such that:
public sealed class Emitter
{
private struct Particle
{
public Vector2 Position;
public Vector2 Velocity;
public ushort Life;
public bool Alive { get { return (Life > 0); } }
}
private readonly Particle[] _particles;
public Emitter(ushort maxParticles)
{
_particles = new Particle[maxParticles];
}
}
The Emitter has other logic that would create, update, and render the particles, but it is not relevant. However, my understanding is that if I were to invoke a method, it would copy the value on each call:
public static void UpdateParticle(Particle p)
{
p.Position += p.Velocity;
}
If I made an Emitter
with 100,000 particles (as unlikely as that would be), copying the particle just to update it seems like it would be doing a lot of unnecessary work. If the method used ref instead UpdateParticle(ref Particle p) { ... }
, then it would just access the data directly and update it there, right?
However, with regards to Jon Skeet's answer for this question, he writes:
You almost never need to use ref/out. It's basically a way of getting another return value, and should usually be avoided precisely because it means the method's probably trying to do too much. That's not always the case (
TryParse
etc. are the canonical examples of reasonable use of out) but using ref/out should be a relative rarity.
Is this one of those "relatively rare" cases where it is the correct choice to use it?
Regarding my design choices for this class:
I did some research into a particle system a while ago. I can't remember the exact reasoning for making
Particle
a struct — something about accessing a contiguous chunk of memory being faster, or not having as many object references — but benchmarking proves that it does perform better than a class.Particle
is a private type, because theEmitter
class is the only thing that will ever care about it. Ever. The client code should never care about individual particles, only that theEmitter
is making pretty sparkles and rendering them._particles
is a fixed size, acting like an object pool, because recycling the allocated memory should be more performance-conscious than invokingnew()
.