1. Technology

Using Extension Methods in VB.NET

Introduced for LINQ, they give you the best of instantiated and shared methods.

By

Updated June 17, 2014

Since it was introduced in VB.NET 2008, LINQ has become fundamental in VB.NET - but it's still widely misunderstood. This article is one of a series at About Visual Basic that covers the major ways to program LINQ. The goal is for a beginning Visual Basic .NET programmer to get up to speed on LINQ. If you found this article from a search and you would like to start at the beginning, you can find an introduction to the overall LINQ technology - what it covers and what you can do with it - in the article LINQ - An Example Driven Introduction with an example showing how LINQ could be used to start web pages using selections made with CheckBox controls. There is an index to all of the articles in the series in the beginning of the article.

Extending Some Other Class

Extension Methods were introduced in VB.NET 2008 primarily to support LINQ - Language INtegrated Query. But they open up a whole new dimension of programming possibilities by themselves.

Here's a definition courtesy of Scott Wisniewski, a developer on the VB Compiler Team:

"Extension methods enable you to create a method in a module decorated with an attribute and have that method appear as if it was an instance method defined on another type."

Huh!? Let's go through that a little slower. Let's start by making sure we understand "shared" and "instantiated".

If a method from another class is declared as "Shared" then you can use it in your code without creating an instance. For example:


Public Class mySharedMethod
    Shared Sub SharedExample()
        MsgBox("This method is shared" &
           " - No instantiation required.")
    End Sub
End Class

Private Sub Button1_Click( ...
   mySharedMethod.SharedExample()
End Sub

If a class isn't shared, then you have to create an instance of the class (in other words, "instantiate" the class to an "object") to use the method.


Public Class myNonSharedMethod
   Public Sub NonSharedExample()
      MsgBox("This method is not shared" &
         " - An instance must be created.")
   End Sub
End Class

Private Sub Button1_Click( ...
   Dim nonShared As New myNonSharedMethod
   nonShared.NonSharedExample()
End Sub

Most of the time, this works great. But suppose the class you want to modify already exists, such as the String class that is part of the .NET Framework. That's what Scott means by, "have that method appear as if it was an instance method defined on another type." "Type" is one of those words that gets used a lot but isn't really well defined. In general, it's almost the same thing as "object". The "type" of the variable "nonShared" above is "myNonSharedMethod". The "type" of "ABCDE" is String.

One way to "extend" a class is to create a new class that inherits the old one. (This doesn't work if the class is "sealed"; that means it can't be inherited.) Here's an example.


Private Class myInheritsExample
   Inherits myNonSharedMethod
   Sub newSub()
      MsgBox("From the newSub method")
   End Sub
End Class

Methods can be used from the original class and the new class now:


Private Sub Button1_Click( ...
   Dim myInherits As New myInheritsExample
   myInherits.NonSharedExample()
   myInherits.newSub()
End Sub

In the example below, the Char type is extended. Since extension methods give you a way to add your own method to the Char class, I created a really simple minded extension to the Char class that will protect strings from curious eyes. It consisting of a really simple cipher: subtract 1 from the ASCII code for any character.


Public Function CharMinusOne(ByVal C As Char) As Char
    Dim ascCode As Integer = Asc(C)
    If ascCode = 0 Then
        ascCode = 255
    Else
        ascCode -= 1
    End If
    Return Chr(ascCode)
End Function

Before this function can be used to extend the .NET String class we must first "create a method in a module decorated with an attribute". Note the limitation, "in a module" however. Because I wanted to clearly show what Shared and non-Shared methods were, I used a class in my code above. But extension methods can only be coded in modules. Since modules can't be instantiated (only classes can), you don't have to use the "Shared" keyword.

You might be unfamiliar with the term "decorated". As Scott uses the term here, it simply means that an "attribute" has been added to the code. Extension methods require a very specific attribute:


<System.Runtime.CompilerServices.Extension()>

The namespace "System.Runtime.CompilerServices" is often named in an Imports statement so only "<Extension()>" is usually needed in the attribute.

With these details, here's the complete code for our extension method:


Public Module AVBStringModule
    <Extension()>
    Public Function CharMinusOne(ByVal C As Char) As Char
        Dim ascCode As Integer = Asc(C)
        If ascCode = 0 Then
            ascCode = 255
        Else
            ascCode -= 1
        End If
        Return Chr(ascCode)
    End Function
End Module

The actual syntax of the extension itself only has one important rule: The type of the first parameter is the data type that is being extended. The first parameter of the extension above - CharMinusOne - is of type Char - "ByVal C As Char" - so that's the type being extended here.

The hard part is (well ... mostly) over now because using extension methods is simple. One of the real achievements of the Visual Basic developers was to make extensions fully incorporated into Intellisense just as soon as they're coded and in scope for the consuming code. That means that if AVBStringEncode is in scope, all we have to do is start coding ...

--------
Click Here to display the illustration
--------

A (slightly - very slightly) practical demonstration would be to disguise a string with this simple cypher.


Dim inputString As String = "This is our secret string."
Dim outputString As New System.Text.StringBuilder(Len(inputString))
For Each C As Char In inputString
    outputString.Append(C.CharMinusOne)
Next
Console.WriteLine(outputString.ToString)

...

Public Module AVBStringModule
    <Extension()>
    Public Function CharMinusOne(ByVal C As Char) As Char
        Dim ascCode As Integer = Asc(C)
        If ascCode = 0 Then
            ascCode = 255
        Else
            ascCode -= 1
        End If
        Return Chr(ascCode)
    End Function
End Module

Our string is now transformed into:


Sghrhrntqrdbqdsrsqhmf-

Coding a method to reverse the transformation would be easy and is left as an excercise for the student.

The example above extends a Char type, but you can define an extension for just about anything. Anything that can be represented in a Visual Basic parameter list. For example, you can include all of these according to Microsoft:

  • Classes (reference types)
  • Structures (value types)
  • Interfaces
  • Delegates
  • ByRef and ByVal arguments
  • Generic method parameters
  • Arrays

Once you get used to them, extension methods can be so attractive that there is actually a danger of overusing them. The Visual Basic team made their second rule for using them, "Be wary of extension methods." (The first rule was to follow Microsoft design guidelines so it doesn't really count.) In fact, Dutch programmers Fons Sonnemans and Loek van den Ouweland have created a web page dedicated to creating a library of useful extension methods that you can download. There are some fairly cool ones. Check out: extensionmethod.net

  1. About.com
  2. Technology
  3. Visual Basic
  4. Using VB.NET
  5. Guide to Using Extension Methods in VB.NET

©2014 About.com. All rights reserved.