Tuesday, December 22, 2009

Extension Methods



Chapter 1 -
New Language Features
Microsoft Visual Studio 2008 Programming
by Jamie Plenderleith and Steve Bunn 
McGraw-Hill/Osborne © 2009























Extension Methods


Extension methods allow the developer to “extend” the functionality of a type in the .NET Framework. You can now add methods as required to existing types. As an example, imagine that you have a method to implement Pascal casing for strings. There are three ways you could use this code in your application:






Note 

Pascal casing, also called “upper camel casing,” is the naming convention in which a group of related words is joined together without spaces and the first letter of each word is capitalized (for example, UpperCamelCase).





  • Add a method to a class, pass strings to the method, and either return a string as a return value or pass the values back out by reference through a parameter.




  • Create a new class that inherits from the String class that just adds the new Pascal casing method.




  • Extend the String class.




Hopefully, the last option has intrigued you. There’s nothing necessarily wrong with the first two options, but extending the String class is a more elegant solution to this problem.


The code sample that follows uses two extension methods on the String type. It also uses a shorter form of the ToPascalCase() method to omit the Return statement. To test this sample, create a new Windows Forms application. Add a code file called Utilities.vb, and add the two sections of code to the Form and Code File, respectively. (Feel free to replace the author’s name with your own name in the code; this has no bearing on the extension methods.) When you run the application, it displays the name using Pascal casing. Visual Basic .NET calls the extension method ToPascalCase() on the String type, which in turn calls the ToProperCase() extension method on each word that comprises the text.





Imports WindowsApplication1.Utilities.StringUtilities

Public Class Form1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim strTest As String = "jamie plenderleith"
MsgBox(strTest.ToPascalCase())
End Sub
End Class

Imports System.Runtime.CompilerServices

Namespace Utilities
Module StringUtilities
<Extension()> _
Function ToPascalCase(ByVal Text As String) As String
For Each Word In Split(Text, " ")
ToPascalCase &= Word.ProperCase & " "
Next
End Function

<Extension()> _
Function ProperCase(ByVal Text As String) As String
Return UCase(Mid(Text, 1, 1)) & LCase(Mid(Text, 2))
End Function
End Module
End Namespace



The following are some important things to note about extension methods:




  • In Visual Basic .NET, extension methods can only be declared in a module.




  • The instance of the object on which it is being called is passed as the first parameter, so this parameter cannot be declared as Optional or as a ParamArray.




Thus, in the following example, the numbers 0, 1, 2, 3, 4, and 5 are passed as the parameter n to the IsEven() extension method. It doesn’t look that way when you’re calling the method, but that’s what’s going on under the hood.




Dim MyIntegers() As Integer = {0, 1, 2, 3, 4, 5}
For Each n In MyIntegers
MsgBox(n.IsEven())
Next

Module IntegerUtilities

<Extension()> _
Function IsEven(ByVal n As Integer) As Boolean
Return n Mod 2 = 0
End Function
End Module



The C# programming language affords us a little extra usability with extension methods. The extension method does not need to be declared inside a module, but rather any static class that is accessible to where you want to make the extension method call. The way an extension method is declared in C# also differs from the way it is declared in VB.NET. For example, the following is an extension method that can be called on arrays. There is nothing particularly interesting about this code sample (it purely acts as a wrapper to the Array.Copy() method), but note the first parameter to the Slice<T>() method.





static class Extensions
{
public static T[] Slice<T>(this T[] source, int index, int count)
{
if (index < 0 || count < 0 || (source.Length - index) < count)
throw new ArgumentException();
T[] result = new T[count];
Array.Copy(source, index, result, 0, count);
return result;
}



And here is a sample piece of C# code implementing this:




private void Form1_Load(object sender, EventArgs e)
{
string[] StringSet = { "1", "2", "3", "4", "5", "6" };
string[] StringSubset = StringSet.Slice(2, 3);

foreach (string s in StringSubset)
{
MessageBox.Show(s);
}
}


























No comments: