Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Fall In Love with Visual Basic All Over Again in Visual Studio 2008 : Page 5

Discover anew why Visual Basic is one of the most successful programming languages in history by exploring some of the new features Microsoft added to Visual Studio and Visual Basic.

Extension Methods
How many times have you wanted to add functionality to a .NET Framework class to provide helper functions for your project? For example, suppose you wanted to create a derived DateTime method class that would return a date formatted in a specific way. If you've ever tried this, you've probably found that, in many cases, the class you want to extend is marked as Sealed, meaning you cannot derive a new MyDateTime class to add your methods to.

VB9 solves this problem with my favorite new feature, Extension Methods. Using extension methods, you can extend a type by adding methods that appear to be instance methods.

Extension methods are just like normal methods but have two important differences. First, you apply the System.Runtime.CompilerServices.Extension attribute to the method to instruct the IDE to treat the method as an extension method. Second, the first parameter of the method is always the type you want to extend. Here's an example. Suppose you want to code an extension to the DateTime class to add a method named ToLogFileString, which returns a string formatted in a specific way for your log file:

<Extension()> _ Function ToLogFileString(ByVal dte As DateTime) As String Return dte.ToShortDateString & " " & dte.ToShortTimeString End Function

Note the attribute on the method. Of course, you must ensure that namespace where the extension method is defined is visible to the code where you call the extension method; in some cases you will need to import the appropriate namespace. Having done that, you can then call the extension method just as though it were an instance method:

strLogFile += Now.ToLogFileString()

The trick behind extension methods is that VB9 helps you out a bit with the syntax of the call. As Figure 10) shows, it even includes the extension method in IntelliSense for the DateTime type!

Figure 10. Intellisense Extension Methods: Extension methods even appear in IntelliSense lists, making them even easier to use.
Behind the scenes, VB9 translates your call (which looks like a call to an instance method) to a shared method call, passing the base object as the first parameter of the call to the extension method. In the example above, the DateTime object returned from the call to Now is provided as the first parameter to the ToLogFileString method.

Because the object gets passed as the first parameter, extension methods can do things that normal instance methods (methods defined in the object's class) can't do. For example, I have always disliked the way the String class's IsNullOrEmpty method is called. Since you can't call methods on an object that is NULL, you must call IsNullOrEmpty as a shared method:


However, if you define an extension method to handle the same function (renamed to IsEmptyOrNull—you can't shadow an existing method on the extended class), the extension method can detect NULL values passed in as the parameter. You can use this to detect NULL strings:

<Extension()> _ Function IsEmptyOrNull(ByVal str As String) As Boolean Return String.IsNullOrEmpty(str) End Function

Now you can call the IsEmptyOrNull extension method even on String variables that are NULL:

blnValidString = str.IsEmptyOrNull()

Be careful, though, this capability has a side effect; it requires you to verify that the first parameter is not NULL before using it. Be sure your extension methods verify that the first parameter is valid before attempting to use it.

Extension methods even work on derived types. You can define an extension method named IsSomething that returns a Boolean value indicating whether the variable is set to an instance of an object:

<Extension()> _ Function IsSomething(ByVal obj As Object) As Boolean Return obj IsNot Nothing End Function

By defining the first parameter as Object, you can now use the IsSomething extension method against any class. Here are several examples:

Dim bln as Boolean Dim strName As String bln = strName.IsSomething() Dim frmMain As System.Windows.Forms.Form bln = frmMain.IsSomething() Dim objThread As System.Threading.Thread bln = objThread.IsSomething()

There are several more important points to make about extension methods:

  • Add any additional parameters you need on the extension method after the first parameter, which must be the object itself.
  • You can overload extension methods just like conventional methods, using the same rules governing method overloading.
  • You may define extension methods in any assembly. They can be defined in the same project or in a separately compiled assembly—you just have to ensure that the method's namespace is visible by the code that will use the extension method.
These three points are demonstrated in the VB9Extensions.vb file in the sample VB9_Tools project. You'll find two different versions of the ToLogFileString method implemented; one has only the special "type" parameter and the other includes a second parameter that the caller must provide. The code below shows calls to both methods:

str = Now.ToLogFileString() str = Now.ToLogFileString(strModuleName)

Using Extension Methods in .NET 2.0
By default, you cannot create extension methods when you target the 2.0 framework. Recall that you use the Extension attribute to declare extension methods. This attribute is new to the .NET Framework version 3.5, and doesn't exist in the 2.0 framework. However, it is possible to "hack" your .NET 2.0 projects slightly to support extension methods.

To support extension methods in .NET 2.0 projects, you must define your own Extension attribute. I recommend creating a separate assembly to define the extension attribute. The sample code contains a project named ExtensionsIn20 containing a code file that defines an ExtensionAttribute class. The class file is very small; here's the complete code.

Namespace System.Runtime.CompilerServices Public Class ExtensionAttribute Inherits Attribute End Class End Namespace

Author's Note: It is important to make sure the Root Namespace property in the project properties is empty. Otherwise, the namespace declaration shown above will be appended to the project's root namespace value.

Compile the ExtensionsIn20 project, and add a reference to it from a Visual Basic project targeting the 2.0 framework where you want to define extension methods. In the module where you define your extension methods, import the System.Runtime.CompilerServices namespace, and decorate your extension methods exactly as you would when using the .NET 3.5 version of the attribute. When it comes time to upgrade your project to .NET 3.5, simply remove the reference to the ExtensionsIn20 assembly, and your code will instead reference the Extension attribute defined in .NET 3.5's System.Runtime.CompilerServices namespace.

Overall, Visual Basic 9 is a compelling upgrade, especially because it's combined with some of the fantastic features in Visual Studio 2008. As discussed, there are some features you should be careful about using, and some that you should avoid completely. The advantages aren't limited to the newest framework version either. Even if your development group has not yet decided to upgrade to the .NET Framework 3.5, the new multi-targeting support means you can easily build .NET 2.0 projects from Visual Studio 2008.

Michael S. Jones is the Director of Systems Architecture for Passport Health Communications, Inc., a national healthcare technology provider connecting hospitals, physician clinics and outpatient centers with payer and patient information to facilitate and improve their revenue cycle process. Michael, his wife, and three children live in Franklin, Tennessee where he spends his spare time reading and enjoying time with his family outdoors. .
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.