Nick’s Code

Search

XNA MVP

Contact

Donate

Categories

Latest News

Twitter


follow nickgravelyn at http://twitter.com



RSS Feed

Let’s Talk C# Features, Pt 4

Posted in .NET, C#, XNA on May 14, 2008 at 1:43pm.
There are 2 comments.

We’ve covered all of the purely compile-time tricks for C# 3.0. Now we’re going to talk about a new feature that will only work on PC (until the .NET CF on Xbox 360 and Zune get updated): extension methods. Extension methods are great for those times when you find yourself writing helper methods for classes and thinking “I wish this was part of the API”. For instance let’s say you have a small Sprite class for your game:

public class Sprite
{
	public Texture2D Texture { get; set; }
	public Vector2 Position { get; set; }
	public Color Color { get; set; }
}

Now we want to add a way to render it using a SpriteBatch. You previously would probably add a method to the Sprite class that looked like this:

public void Draw(SpriteBatch spriteBatch)
{
	spriteBatch.Draw(Texture, Position, Color);
}

And then to render you would create a Sprite and SpriteBatch and call that method:

Sprite sprite = new Sprite();
SpriteBatch spriteBatch = new SpriteBatch(GraphicsDevice);

sprite.Draw(spriteBatch);

Not too bad, right? Except it doesn’t quite look right. The method looks like the Sprite is drawing the SpriteBatch. Clearly not what we want. Ideally we want something like this:

spriteBatch.Draw(sprite);

Well now you can using extension methods. An extension method is simply a static method where the first parameter is qualified with the ‘this’ keyword. So we could take our Draw method above and place it into a new, static class like this:

public static class SpriteBatchExtensions
{
   public static void Draw(
        this SpriteBatch spriteBatch,
        Sprite sprite)
   {
	spriteBatch.Draw(
                sprite.Texture,
                sprite.Position,
                sprite.Color);
   }
}

So this is just a standard public static method but that ‘this’ keyword adds a whole new functionality to it. We can still call this method just like we would before extension methods:

Sprite.Draw(spriteBatch, sprite);

But because we have the ‘this’ keyword on that first parameter we can now call it like we wanted to:

spriteBatch.Draw(sprite);

What does this all mean in the grand scheme of things? APIs are no longer set in stone. You can now make these methods that attach to the types that they work for. They still act like normal static methods in that you don’t get any access to protected or private data, and you do still have to have access to the method (so it can’t be a private or protected static method or in a non-public class), but now you can have more logically written code where actions are actually performed on the objects they affect.

As another quick example, let’s look at some pretty standard code most people run when they draw a model in XNA:

foreach (ModelMesh mesh in myModel.Meshes)
{
	foreach (BasicEffect effect in mesh.Effects)
	{
		effect.EnableDefaultLighting();
		effect.World = world;
		effect.View = view;
		effect.Projection = projection;
	}
	mesh.Draw();
}

We could easily stick that into an extension method like this:

public static void Draw(
                this Model model,
                Matrix world,
                Matrix view,
                Matrix projection)
{
	foreach (ModelMesh mesh in model.Meshes)
	{
		foreach (BasicEffect effect in mesh.Effects)
		{
			effect.EnableDefaultLighting();
			effect.World = world;
			effect.View = view;
			effect.Projection = projection;
		}

		mesh.Draw();
	}
}

And now when we want to render out a model we can just call it as if the Model had this Draw method all along:

myModel.Draw(world, view, projection);

It’s a very slick feature and very powerful. Unfortunately this doesn’t work on Zune or Xbox 360 for now, but hopefully it will get support in the not-to-distant future.



By Spodi on May 24, 2008 at 2:14 am

I think this is the best feature to hit C# this release. I had writing classes like, for example, “StringExtensions” for extra string processing that you would expect to be in the String class. Not only do you now have two classes to look through, but its also less obvious that it should be part of the “String” class. I think the clear indication of extensions is a HUGE plus. When I heard of this originally, I was afraid it was going to cause some obfuscation on where are of these methods are coming from - whether they are part of the original object or an extension. I’m glad to see that they made sure its not a problem.

By hspirdal on June 12, 2008 at 10:21 pm

Thanks for some great introductions to the new 3.0 features of the C# language! You might want to explain extensions a bit more, though.

http://www.gamedev.net/community/forums/topic.asp?topic_id=497634 introduces a pitfall I ran into when trying this out because I diddn’t really know the reasoning behind extensions. (Which of course is my bad, but it might make it clearer for future readers)



Post A Comment