KnowDotNet Visual Organizer

What's New In VS2008?

Extension Metods

by Les Smith
Print this Article Discuss in Forums

Did you ever want to have a ToInteger Method on an object of Type String?  Did you ever want to add ofther methods to the various types of System.Object?  In VS2008, you now can do that with Extension Methods.

Much of what this article discusses came with the advent of LINQ, which you will hear much of in VS2008,  However, I will limit this discussion to extending System.Objects.  One of the new features in Visual Studio is Extension Methods, which allows you to extend System.Objects, such as Integers, Strings, etc.  In this article, I am going to extend several objects.  

First, Extension Methods derive from System.Runtime.CompilerServices and so you have to have an Import of that Namespace.  Secondly, Extension Methods must appear in a Module in VB.NET.  A module is nothing more than a class of Shared Methods, etc.  Therefore, the Extension Methods must have an access level of Public.  Thirdly, to create an Extension Method, you must use an Extension Attribute as shown in the code snippet below.  Finally since I am going to use a Regular Expression I will need to import System.Text.RegularEcpressions.

I will extend the String Object Type by adding several methods to the methods of a String object.  Although these are very simple methods, you will get the picture of how you can extend the methods of the System.Object Namespace objects.  Now before you decide to replace all of your utility functions by adding too many methods to the String object in the CLR.  You might want to think of what that might do to intellisense.

Imports System.Object.Runtime.CompilerServices
Imports System.Text.RegularExpressions

Module Module1
  
Sub Main()
      Class1.TestExtensions()

  
End Sub

   ' Extension Methods
   <Extension()> _
  
Public Function IsValidSSN(ByVal ssn As String) As String
      Return Regex.IsMatch(ssn, "((\d\d\d-\d\d-\d\d\d\d)|(\d{9}))")
  
End Function

   <Extension()> _
  
Public Function IsUpper(ByVal s As String) As Boolean
      Dim m As Match = Regex.Match(s, "^[A-Z]")
      
Return m.Success
  
End Function

   <Extension()> _
  
Public Function IsLower(ByVal s As String) As Boolean
      Return Not s.IsUpper
  
End Function

   ' This method returns True if the whole string alpha
   <Extension()> _
  
Public Function IsAllAlpha(ByVal s As String) As Boolean
      Dim m As Match = Regex.Match(s, "^[A-Za-z]*")
      
Return s.Length = m.Length
  
End Function

   ' Create an ToInteger method on an object of type String
   ' The desire for this method grew out of the extensive use of Val()
   ' when I was coding in VB6 and the fact that no such method exists in
   ' pure VB.NET.  This method works similiar to Val() in that it stops
   ' at the first occurrence of a non-numeric character.  It will return a
   ' value of 0 if the first charachter of the string is not numberic.
   <Extension()> _
  
Public Function ToInteger(ByVal s As String) As Integer
      Dim m As Match = Regex.Match(s, "^[0-9]*")
      
If m Is Nothing OrElse m.Length = 0 Then
         Return 0
      
Else
         Return CType(m.Value, Integer)
      
End If

   End Function

   <Extension()> _
  
Public Function EqualsCaseInsensitive(ByVal s1 As String, _
      
ByVal s2 As String) As Boolean
      Return s1.Equals(s2, StringComparison.InvariantCultureIgnoreCase)
  
End Function

   <Extension()> _
  
Public Shared Function ProperCase(ByVal inputString As String) As String
      If inputString.Length > 0 Then
         If (inputString.ToUpper.Equals(inputString)) OrElse _
            (inputString.ToLower.Equals(inputString))
Then

            Dim words() As String = inputString.Split(" ")

            
For i As Integer = 0 To words.Length - 1
              
If InStr(words(i), ".") = words(i).Length _
                  
OrElse InStr(words(i), ".") = 0 Then

                  Dim word() As String = words(i).Split("-")
                  
For j As Integer = 0 To word.Length - 1
                    
If i > 0 Then
                        If "and_of_a_the".IndexOf(word(j)) > -1 Then
                           word(j) = word(j).ToLower
                        
Else
                           word(j) = ProperWord(word(j))
                        
End If
                     Else
                        word(j) = ProperWord(word(j))
                    
End If
                  Next
                  words(i) = Join(word, "-")
              
Else
                  If Len(words(i)) = 2 Then
                     words(i) = words(i).ToUpper
                  
End If
               End If
            Next
            inputString = Join(words, " ")
        
End If
      End If
      Return inputString
  
End Function

   Private Shared Function ProperWord(ByVal word As String) As String
      If word.Length > 0 Then
         If word = word.ToUpper Or word = word.ToLower Then
            word = word.Substring(0, 1).ToUpper & word.Substring(1).ToLower
        
Else
            word = word.Substring(0, 1).ToUpper & word.Substring(1)
        
End If
         If UCase(Left(word, 2)) = "MC" Then
            word = "Mc" & Mid(word, 3, 1).ToUpper & Mid(word, 4)
        
End If
      End If
      Return word
  
End Function
End
Module


The following is the code to test the Extension methods that I have added to the String object.

Public Class Class1
  
Public Shared Sub TestExtensions()
      Debug.Print(
"That A is upper case is " & "A".IsUpper)
      Debug.Print(
"That A is lower case is " & "A".IsLower)
      Debug.Print(
"That A = a ignoring case is " & _
        
"A".EqualsCaseInsensitive("a"))
      Debug.Print(
"That abc1d is all alpha is " & "abc1d".IsAllAlpha)
      Debug.Print(
"Val of 123a = " & "123a".ToInteger.ToString)
      Debug.Print(
"Valid SSN format = " & "123-46-2134".IsValidSSN)
      Debug.Print(
"Valid SSN format = " & "123456789".IsValidSSN)
      Debug.Print(
"Valid SSN format = " & "12345678".IsValidSSN)
      Debug.Print(
"Valid SSN format = " & "123-23-123".IsValidSSN)
      Debug.Print(
"Proper case of john MCCULLOUGH = " & _
        
"john mccullough".ProperCase)
  
End Sub
End
Class


The following are the results, taken from the Output Window, that come from the test of the Extension methods.

That A is upper case is True
That A is lower case is False
That A = a ignoring case is True
That abc1d is all alpha is False
Val of 123a = 123
Valid SSN format = True
Valid SSN format = True
Valid SSN format = False
Valid SSN format = False
Proper case of john MCCULLOUGH = John McCullough


This should whet your appetite for what you can now do in extending the .NET Framework in VS2008.

Have you tried our newest product, Visual Class Organizer?  You'll be amazed how easy it is to keep the code in your code windows organized.  TRY IT FREE FOR 30 DAYS BY CLICKING HERE.



Ask a Question, or give your feedback on my articles or products by going to the KnowDotNet Forum or by clicking on My Blog.
  

Writing Add-Ins for Visual Studio .NET
Writing Add-ins for Visual Studio .NET
by Les Smith
Apress Publishing