Extension Methods
Consider the System.IO.DirectoryInfo class, which is used to manipulate filesystem directories. This class supports functionality to list the files and subdirectories (DirectoryInfo.GetFiles()) as well as the capability to move the directory (DirectoryInfo.Move()). One feature it doesn’t support directly is the copy feature. If you needed such a method, you would have to implement it, as shown earlier in Listing 5.37.
The DirectoryInfoExtension.Copy() method is a standard static method declaration. However, notice that calling this Copy() method is different from calling the DirectoryInfo.Move() method. This is unfortunate. Ideally, we want to add a method to DirectoryInfo so that, given an instance, we could call Copy() as an instance method—directory.Copy().
C# 3.0 simulates the creation of an instance method on a different class via extension methods. To do this, we simply change the signature of our static method so that the first parameter—that is, the data type we are extending—is prefixed with the this keyword (see Listing 5.41).
LISTING 5.41: Static Copy Method for DirectoryInfo
public static class DirectoryInfoExtension
{
public static void CopyTo(
this DirectoryInfo sourceDirectory
, string target,
SearchOption option, string searchPattern)
{
// ...
}
}
__________________________________________________________________________________
// ...
DirectoryInfo directory = new DirectoryInfo(".\\Source");
directory.CopyTo(".\\Target",
SearchOption.AllDirectories, "*");
// ...
With this simple addition to C# 3.0, it is now possible to add “instance methods” to any class, including classes that are not within the same assembly. The resultant CIL code, however, is identical to what the compiler creates when calling the extension method as a normal static method.
Extension method requirements are as follows.
- The first parameter corresponds to the type that the method extends or on which it operates.
- To designate the extension method, prefix the extended type with the this modifier.
- To access the method as an extension method, import the extending type’s namespace via a using directive (or place the extending class in the same namespace as the calling code).
If the extension method signature matches a signature already found on the extended type (that is, if CopyTo() already existed on DirectoryInfo), the extension method will never be called except as a normal static method.
Note that specializing a type via inheritance (covered in detail in Chapter 6) is preferable to using an extension method. Extension methods do not provide a clean versioning mechanism, because the addition of a matching signature to the extended type will take precedence over the extension method without warning of the change. The subtlety of this behavior is more pronounced for extended classes whose source code you don’t control. Another minor point is that, although development IDEs support IntelliSense for extension methods, simply reading through the calling code does not make it obvious that a method is an extension method.
In general, you should use extension methods sparingly. Do not, for example, define them on type object. Chapter 6 discusses how to use extension methods in association with an interface. Without such an association, defining extension methods is rare.
End 3.0