Customizable Navigation Bar

Friday, August 30, 2013

Extension Methods In Unity

As a Unity developer, the ability to use C# for scripting allows for some of the great features that come with it. This includes extension methods. Extension methods allow for extensions to classes that already exist, and keep your code nice and clean, so I wanted to go into them with a little detail today.

So what is an extension method? And what advantages and disadvantages does it have?

MSDN states that "Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type". Couldn't say it better myself. Extension methods are basically syntactic sugar, allowing to you call your own methods from a class such as GameObject, or string, as if they were always a part of the class. This gives your code a much cleaner look.

There are a few disadvantages to using extension methods though, you can't just have the cake and eat it too.

  1. One of the disadvantages of extension methods is that you cannot create static methods for a class. Every extension method you create will be instance based. This is because extension methods are already a special type of static method, and the first parameter of the extension method is the instance of the object you are calling it on, so there is no way to get a static method out of it. You will see what I mean later when I show you some examples.
  2. Another disadvantage is that you cannot have extension properties, indexers, operators or constructors. So while you get the convenience of adding additional methods to a class, you still need to define a new class if you want extra properties, indexers or constructors.
  3. Reflection doesn't know what you are talking about. As I said before, extension methods are just syntactic sugar, so extension methods aren't actually a part of the class the method applies to. You can still technically call your extension methods from reflection, but you need to do some searching through your assemblies and the attributes applied to the methods.
  4. Extension methods will not take the place of functions that are already defined. If you came up with a better way find something in a list, you can't just create an extension method with the exact same name and parameters. The compiler will look at the already defined methods before it looks at the extension methods, so if you have a method that is faster or better than the already defined method, just call it something similar that you will remember.
So what does an extension method look like anyways? 

The first example I am going to show you is an extension of the Transform class in Unity. The transform class defines a method called transform.Find(), where you pass in a path to the child transform you are looking for. An example of this would be transform.Find("arm/hand/finger");

Sometimes this method is a little finicky, and you also need to know what the path is beforehand, so if anything changes in the hierarchy, you have to edit your code and recompile. I'm not a fan of this, so I wrote an extension method for Transform, called Transform.Search(). All you need to do is pass in the name of the child you are looking for, and it will return it if it find it, or it will return null if the name passed does not exist in the hierarchy.


//The first thing you want to do is define a static class. We will call this class TransformExtension
public static class TransformExtension
{

//Next we will create a static method, and this is the extension method that will be applied to the Transform class. We will call this method Search. Pay attention to the parameters of this method, especially the first one.  

public static Transform Search(this Transform transform, string name)
{
//The first parameter passed has the 'this' keyword, and the type of the class that this extension method applies to. This is so the compiler knows which instance of the class the extension method is being applied to.

  //Now we fill out the method as we normally do

  //its faster to compare two ints than it is to compare two strings, so we compare the length first, then check the string if the lengths are the same, if this is the transform just return it
  if(transform.name.Length == name.Length)
  {
    if(transform.name == name)
    {
      return transform;
    }
  }
        
//do the same for the children
for(int i = 0; i < transform.childCount; ++i)
{

//this function is also recursive, so we just call search through this child as well
  Transform result = Search(transform.GetChild(i), name);

  if(result != null)
  {
    return result;
  }
}

return null;
}
}

And that's it! Now you have a quick and much simpler way to search through your transform for a child.

Extension methods also work on generic classes as well. So you can provide extension methods for classes such as List<String>.

//remember to create a static class
public static class StringListExtension
{

//Static method that returns true or false if the list contains the string passed. Remember that the first parameter is the keyword 'this', and the type that this extension method applies to.
public static bool fastContains (this List<string> list, string name)
{

  for (int i = 0, iMax = list.Count, nameLength = name.Length; i < iMax; i++)
  {

    //Checking two ints is faster than checking two strings, so we check the length first
    if (list [i].Length == nameLength)
    {
      //if the length of the string is the same, then compare the two strings together to see if they are the same
      if (list [i] == name)
      {
        return true;
      }
    }
  }

return false;
}
}

And that's it! If you want to use this extension method, its as simple as stringlist.fastContains(stringvalue); and it will return true or false if the list contains the string passed.

These two examples are just some of the many ways that extension methods can be used. They offer a clean way to add functionality to classes that are already existing, and who knows maybe in the future we will get some extra functionality to them. I personally wouldn't mind seeing extension properties or constructors in the future.

That's all for now though, so good luck with your projects!