Sunday, April 18, 2010

No Covariance in Projections? No Problem!

I figured out a way around the fact that until XNA 4.0 gets updated for Xbox development, you can't use a Projection<Y> where it calls for a Projection<X> even if Y inherits from or implements X.

Just for completeness' sake, an example projection would be having a generic class that takes a type parameter.  Specifically, I was working on a CollisionEffect<T> class, where T is any class that implements an interface named ICollideable, indicating that the class' objects can take part in collisions.  In this case, CollisionEffect<T> is a projection from T -> CollisionEffect<T>.  A CollisionEffect<Player> is an effect that can be applied to a Player during a collision.  Since I wanted objects to be able to hold effects intended for different kinds of collideable objects, I figured that having ICollideable also provide an IEnumerable<CollisionEffect<ICollideable>> would do the trick.

Well, because C# 3 doesn't allow covariance in projections, I couldn't store a CollisionEffect<Player> as a CollisionEffect<ICollideable>.

The solution?  An ICollisionEffect interface that provided non-generic versions of the information in a CollisionEffect, i.e. versions using the base Object class.  By having CollisionEffect explicitly implement ICollisionEffect, a Player can have a List where the elements can be any allowable CollisionEffect<T>.  During a collision, a collideable object will call the other ICollideable's GetEffects<T> method, which retrieves from the List<ICollisioneffect> any CollisionEffect<T> objects where the type parameter matches.

Once I can actually have projection covariance in C# for Xbox programming then I'll get rid of ICollisionEffect since it would become completely extraneous, but for now it's a useful trick that lets me have almost exactly what I wanted.

No comments:

Post a Comment