Archive for August, 2007

Introduction to the StringBuilder Class

StringBuilder helps you build a program as strong as a brick wallIf you’ve been around VB a while you know that concatenating strings, particularly large strings over about 1K, can be a time consuming task for your applications. To deal with this, Microsoft introduced the StringBuilder class in the .NET Framework in the System.Text Namespace. In this article we’ll look at the advantages of using it and go over some of the fundamentals of using it.

Why Use StringBuilder?

You still see a lot of code around that uses the old string concatination methods. That’s not surprising because it’s comfortable and familiar to use for most VB’ers. But, there are two good reasons to use StringBuilder for large or looped string concatenation operations: speed and readability.

Speed is really a no-brainer. Using StringBuilder averages around 10 times faster than the concatenation operator ‘&’ or the String.ConCat function. It’s highly optimized for fast string operations. Even C++ .NET programmers have trouble outperforming it.

Readability is the other advantage. How often have you seen, or even written, code like this:

sSQL = "UPDATE Profile " & _
       "SET FName='" & txtFName.Text & "', " & _
       "MName='" & txtMName.Text & "', " & _
       "LName ='" & txtLName.Text & "', " & _
       "NickName='" & txtNickname.Text & "', " & _
       "Address='" & txtAddress.Text & "', " & _
       "Phone='" & txtPhone.Text & "', " & _
       "Email='" & txtEmail.Text & "', " & _
       "Status='" & cboStatus.Text & "', " & _
       "Notes='" & txtNotes.Text & " " & _
       "WHERE (ProfileID = " & txtProfileID.Text & ");"

or code like this

sSQL = "UPDATE Profile "
    sSQL = sSQL & "SET FName='" & txtFName.Text & "', "
    sSQL = sSQL & "MName='" & txtMName.Text & "', "
    sSQL = sSQL & "LName = '" & txtLName.Text & "', "
    sSQL = sSQL & "NickName = '" & txtNickname.Text & "', "
    sSQL = sSQL & "Address = '" & txtAddress.Text & "', "
    sSQL = sSQL & "Phone ='" & txtPhone.Text & "', "
    sSQL = sSQL & "Email='" & txtEmail.Text & "', "
    sSQL = sSQL & "Status= '" & cboStatus.Text & "', "
    sSQL = sSQL & "Notes='" & txtNotes.Text & " "
    sSQL = sSQL & "WHERE (ProfileID = " & txtProfileID.Text & ");"

This code is usually difficult to read and even more difficult to debug, especially if it goes on for 20, 30 or even 50+ lines like I’ve seen some code. It can even be difficult to code this originally since it’s quite easy to mistype something.

Append, AppendLine, and AppendFormat

We’ll begin looking at StringBuilder by taking a look at how we could build the same SQL statement above using StringBuilder and then taking a look at the Append commands. (Note that I don’t recommend building SQL statements dynamically like this due to SQL injection risks but it’s a good common string building example.)

Here’s the StringBuilder code:

Dim SqlBuilder As New System.Text.StringBuilder
With SqlBuilder
    .Append("UPDATE Profile ")
    .AppendFormat("SET FName='{0}', ", txtFName.Text)
    .AppendFormat("MName='{0}', ", txtMName.Text)
    .AppendFormat("LName='{0}', ", txtLName.Text)
    .AppendFormat("NickName='{0}', ", txtNickname.Text)
    .AppendFormat("Address='{0}', ", txtAddress.Text)
    .AppendFormat("Phone='{0}', ", txtPhone.Text)
    .AppendFormat("Email='{0}', ", txtEmail.Text)
    .AppendFormat("Status='{0}', ", cboStatus.Text)
    .AppendFormat("Notes='{0}' ", txtNotes.Text)
    .AppendFormat("WHERE (ProfileID = {0}); ", txtProfileID.Text)
End With

That’s a lot cleaner and easier to read, isn’t it? Now let’s look at the Append commands.

The Append function adds the specified value to the end of the builder. One neat thing about Append is that it not only takes a string argument but it has 19 overloads that allow you to append the major data types (Int, Long, etc.), a substring of a specified string, or the default .ToString value of an object. This makes it very powerful and easy to use as compared to standard concatenations that require type conversion (if you’re running Option Strict like you should be doing). Since it does the type conversions for you internally, this helps even more with the speed.

AppendFormat also adds the specified value to the end but also applies a format to it. In the example above, we’re using a custom format string for each line of the SQL statement that allows us to insert the value into the single quoted location without additional concatenation overhead. This method also accepts objects and does the conversion internally as part of the formatting logic.

The AppendLine adds the ‘default line terminator’, aka the CR/LF pair on all Windows systems, to the end of the builder. Optionally, you may also include a string as seen here:

With EmailBuilder
    .AppendLine()
    .AppendLine("Sincerely,")
    .AppendLine()
    .AppendLine(txtSignatureName.text)
End With

Oh, just in case you didn’t know, the standard .ToString method allows you to retrieve the internal string from StringBuilder. Also note that I like to use With blocks for it since it makes it easier to read, for me anyway.

Insert

Insert is a lot like Append in that it has overloads for most data types. However, with it, you can specify where in the character sequence the string (or string representation of an object) goes. A limitation of Insert is that unless you get the string that’s being built using the .ToString method and use the IndexOf method on the result you can’t get the position where you want to insert. This limits its usefulness a bit but it can be quick if you need to insert a hunk of text in the middle of a large string as seen in this example:

' Email built using a template
If txtPersonalMessage.Text.Length > 0 Then
    EmailBuilder.Insert(EmailBuilder.ToString.LastIndexOf("Sincerely,") - 1, txtPersonalMessage.Text)
End If

Replace

Replace, as the name implies, allows you to replace a given string with another string. This is especially powerful for templating applications when you can replace a key value in the template with a value from a database query or a business object as shown in this example:

With EmailBuilder
    .Replace("{customer_fullname}", CurrentCustomer.FullName)
    .Replace("{customer_firstname}", CurrentCustomer.FirstName)
    .Replace("{customer_city}", CurrentCustomer.City)
    'more replacements after this
End With

Remove

Remove, as you might expect, allows you to remove a specified number of characters starting at a particular position. Once again, finding the position is a little tricky. It can be useful if you need to remove a paragraph from a template, as in this example:

'we're assuming we already have the position info we need
EmailBuilder.Remove(HolidayGreetingIndex, HolidayGreeting.Length)

That wraps up the basics of using the StringBuilder class. I hope you’ve found this article helpful in learning about this class and how to use it. Let me know if you liked this article or have comments/question by leaving a comment, using the contact me button, or using the rating stars.

Share This Article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • DotNetKicks
  • DZone

Add comment August 31st, 2007

Link Round-Up For 8/29/07

Links make the Internet go roundHere are some interesting items I’ve found this week.

Last week I had mentioned an article at TechRepublic about recommending an IT career to the next generation. Here’s another good one over at WindowsITPro, Are IT Pros Steering Their Children Away From IT?. While the discussion on this one wasn’t quite as lively, there were some good points made. I particularly liked this one by ROGJR

The industry uses so many recruiting agencies, short term contracts, and outsourcing that any position as an IT pro would be considered unstable. It’s close to being treated like a day laborer.

as well as this one by Formica

Now I realize that instead of working my tail off on a computer science degree, I should have been working on a business degree — easier classes and a position that sets the salaries and policies instead of being victimized by them.

Ouch! I’ve started work on my own article on this subject I hope to have ready soon.

Over at Digital Blasphemy, Jeremy Jarrell has this nice debugging tip: Overriding ToString for Easier Debugging. While it’s written for C# it’s easy to apply the same idea to VB.NET debugging as well.

‘Ciz’ had left me a comment earlier this week on my article, How To Conduct a VB.NET Job Interview, and mentioned his related article, Recruiting VB.NET developers. I don’t agree with his point about hiring a C# developer to do VB.NET work but I do agree with his ending statement:

The real expertise in .NET is an understanding of the framework, object-oriented design, and good general development practices.

To see why I think C# programmers shouldn’t be hired to program VB.NET, check out this article on Los Techies: VB.Net oddity of the day - Assignment/Comparison operator. While this is a relatively trival matter, C# programmers are likely to get annoyed by long-standing BASIC syntax just like VB’ers find typing a lot of semi-colons and braces bothersome.

If you’ve wondered about using an Interface or Abstract Class, Kirill Osenkov has an answer for you in this article: Choosing: Interface vs. Abstract Class. He raises several good points in where NOT to use an interface and opts for a very minimalist approach. I’m not sure if I agree with him 100% but he does raise some very good points.

EDIT: One quick addition this week. If you’re a former VB6′er and miss the Line and Shape controls, check out the Visual Basic 2005 Power Packs 2.0 from Microsoft. This new pack, released on 8/13/07, adds enhanced versions these controls as well as incorporating the previously available PrintForm and Printer Compatibility components.

That’s all for this week. If you know of an article on VB.NET or general programming that I should be aware of, please leave me a comment or use the contact me button.

Share This Article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • DotNetKicks
  • DZone

2 comments August 30th, 2007

Introduction to Operator Overloading in VB.NET

Overloaded with OperatorsOperator overloading has been around quite some time in object oriented languages like C++ but it’s a new feature in VB.NET with the .NET Framework 2.0. In this article, we’ll look at what operator overloading is and how we can use it in our VB.NET programs.

What is Operator Overloading?

Operator overloading is a type of polymorphism that applies to operators, like plus (+) or equals (=), and gives them different implementations. Using it you can redefine overloadable operations within your classes and structures and make your code cleaner and easier to read. It will also make it easier for you to interact with object that already expose overloaded operators.

Which VB.NET Operators Can Be Overloaded?

VB.NET allows the following operators to be overloaded:

  • + (increment/plus - unary and binary)>
  • - (decrement/minus - unary and binary)
  • Not (unary)
  • IsTrue (unary)
  • IsFalse (unary)
  • CType (unary)
  • * (multiply - binary)
  • / (divide - binary)
  • \ (integer divide - binary)
  • & (concatinate - binary)
  • Like (binary)
  • Mod (binary)
  • And (binary)
  • Or (binary)
  • Xor (binary)
  • ^ (raise to power - binary)
  • << (left shift - binary)
  • >> (right shift - binary)
  • = (equals - binary)
  • <> (not equals - binary)
  • < (less than - binary)
  • > (greater than - binary)
  • <= (less than or equal to - binary)
  • >= (greater than or equal to - binary)

Unary operators only have one argument while binary operators require two. Obvious, I know, but some novices stumble on this at first.

You don’t have to overload all of the operators in your class, just use the ones you need. However, you must include overloads for these logical pairs of comparative operators :

  • = and <>
  • < and >
  • <= and >=
  • IsTrue and IsFalse

How Do You Code It?

‘Operator’ is a method keyword just like Function and Sub. The difference is that the name you use is simply the operator as seen here:

Public Shared Operator +(ByVal message1 As EmailMessage, ByVal message2 As EmailMessage) As EmailMessage
    Dim ReturnValue As New EmailMessage
    'code here to combine objects into new object
    Return ReturnValue
End Operator

Operators must always be declared as Shared and must always return a value. You cannot use an Exit statement with them, you must always use return. Another consideration is that the parameters or the return value must be the same as the containing class. For unary operators, the single parameter must be the containing class although the return value doesn’t have to be. For binary operators, at least one of the parameters must be the containing class.

Our code for calling the operator is quite simple, as seen here:

Dim OperationsAlertEmail As New EmailMessage
Dim SalesAlertEmail As New EmailMessage
'Build Alert Emails here
'Combine them for executive distribution
Dim ExecutiveAlertEmail As EmailMessage = OperationsAlertEmail + SalesAlertEmail

Also, you can have overloads to your binary operators. For example, let’s assume that in our example we have different classes for each type of email but we want to be able to combine them in some cases. Therefore we might have a set of overloaded operator methods like so:

Public Shared Operator +(ByVal message1 As SalesEmailMessage, ByVal message2 As ExecutiveEmailMessage) As ExecutiveEmailMessage
    Dim ReturnValue As New ExecutiveEmailMessage
    'code here to combine objects into new object
    Return ReturnValue
End Operator

Public Shared Operator +(ByVal message1 As OperationsEmailMessage, ByVal message2 As ExecutiveEmailMessage) As ExecutiveEmailMessage
    Dim ReturnValue As New ExecutiveEmailMessage
    'code here to combine objects into new object
    Return ReturnValue
End Operator

As mentioned above, only one of the parameters in a binary operation have to be of the containing type. This can allow you to code something like this:

Public Shared Operator &(ByVal message1 As EmailMessage, ByVal messageText As String) As String
    Return message1.MessageHeader & message1.MessageText & messageText
End Operator

...................

Dim NewMessageText As String = ExecutiveAlertEmail & txtUpdatedMessage.Text

As you can see, using an overloaded operator can make it easy for your class to combine with other objects. In the example above, if the operator wasn’t there the concantination operation wouldn’t compile due to an “Operator Not Defined” error. While our example is rather simple, remember that you can expand this concept to encompass more complex solutions.

However, you do want to avoid any unnecessary complexity in your operator code. Don’t include things like database access, file access, and so forth in operator code. You want the performance of operators to be as fast as possible. Also, you want to make the operation intuitively logical as well. For example, if you have a plus operator, don’t make it subtract or divide! The bottom line is that another programmer shouldn’t have to look at your code to understand what is happening, they should be able to determine it intuitively. If they can’t, then an operator may not be the appropriate choice for that routine.

I hope you found this introduction to operator overloading informative and useful. Let me know what you think by leaving a comment or question, using the contact me button or just using the rating stars. That way I know if I’m covering is what you want to see, if it is helpful or not, or if you would like more information about a subject.

Share This Article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • DotNetKicks
  • DZone

3 comments August 30th, 2007

Introduction to the Generic List - Part II

Thirsty for more info about the Generic List?In Part I, I covered the basics of the List object as well as inserting and removing items and sorting items. In this part I’ll be covering searching, conversion, and enumeration functions available in the List object.

Searching

The List object offers several powerful search methods. The first is quite simple, Contains. It searches the List to see if it contains an object that matches the parameter as seen here:

If EmailAddresses.Contains(txtEmailAddress.text) Then

If you need to have more sophisticated existence searching you can use the Exists method. It takes a Predicate Delegate so you can write your own code for this purpose:

If EmailAddresses.Exists(AddressOf AddressLoaded) Then
.............
Private Function AddressLoaded(ByVal emailAddress As String) As Boolean
    If emailAddress = txtEmailAddress.Text Then
        Return True
    Else
        Return False
    End If
End Function

IndexOf and LastIndexOf return the position of the specified item in the List should you want the index rather than the specific item itself.

Next we have the Find methods (Find, FindAll, FindLast, FindIndex, FindLastIndex) that also use Predicate Delegates. I covered these delegates in my previous article, How to Use the Action and Predicate Delegates, so I won’t cover them again here.

TrueForAll is another handy Predicate Delegate based search method that will tell you if a particular condition is true for all the items in the List:

If EmailAddresses.TrueForAll(AddressOf ValidateEmailAddress) Then

Our last searching method is BinarySearch. It uses a binary search algorithm, essentially the default Comparer or one you specify, to locate a specific item in the List. Note that the list should be sorted with the same Comparer first or else it won’t work correctly. This method is particularly handy for inserting new items into a particular place in the List. I don’t have a good example of this one but if there is demand for it I’ll include it in a future article dealing with comparers.

Conversion

The List also provides us with a number of ways to convert the data within it.

The AsReadOnly returns a ReadOnlyCollection:

Dim OptOutEmails As IList(Of String) = EmailAddresses.AsReadOnly

ConvertAll takes the content of the List and, using a Converter Delegate, creates a new list with a different type of item:

Dim Emails As New List(Of System.Net.Mail.MailMessage)
Emails = EmailAddresses.ConvertAll(New Converter(Of String, System.Net.Mail.MailMessage)(AddressOf ConvertToEmailMessage))

................

Private Function ConvertToEmailMessage(ByVal emailAddress As String) As System.Net.Mail.MailMessage
    'email message building code would go here
End Function

We saw the CopyTo method used above when copying a ListBox’s SelectedItems collection to a List. This CopyTo works the same way:

Dim EmailsSent(EmailAddresses.Count - 1) As String
EmailAddresses.CopyTo(EmailsSent)

Of course, it’s a lot easier to use the ToArray function to do the same thing:

Dim EmailsNotSent() As String
EmailsNotSent = EmailAddresses.ToArray

The GetRange method allows you to extract a portion of the List as a list in its own right:

Dim ProcessNow As List(Of String) = EmailAddresses.GetRange(0, EmailAddresses.Count \ 2)
.
.
.

Enumeration

As we discussed in the previous article on Actions and Predicates, ForEach uses Action Delegates to do something with each member of a List. For example:

Emails.ForEach(AddressOf SendEmail)

If you need more control, you can get the enumerator and manipulate it yourself with the GetEnumerator method.

I hope you’ve found these two overview articles helpful. If you did or didn’t please let me know by leaving a comment. It’s your feedback either through comments, contact me emails, or rating stars that help me chart the direction of this blog’s articles.

Share This Article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • DotNetKicks
  • DZone

Add comment August 29th, 2007

Introduction to the Generic List - Part I

A Generic List is a lot better than a generic beer!Earlier I had gone over some other aspects of the System.Collections.Generic namespace, such as the Queues, Stacks, and Action and Predicate Delegates. I received a couple of emails asking me to also go over the plain old List object as well and include any helpful tricks I might have for them. So, this will be the topic for this two part series of articles.

The Basics

The generic List is a type-safe version of the .NET ArrayList. It can dynamically change its size as items are added or removed. It can also be searched, sorted and enumerated. Since the List is type-safe, meaning you have to specify the type of items going into it, it will generally perform better than ArrayList. All in all, the generic List is a better way to store data in memory in most cases than the older ArrayList and plain old array models.

Adding and Removing Items

While The Add, Remove, and Clear methods are obvious, there are some additional related methods that you might find useful.

We’ll look at AddRange first. As you can guess, it loads more than one item at once to the List. It might be a bit daunting for you when you look at the parameter required for this method.

collection As System.Collections.Generic.IEnumerable(Of T)

What does that mean? What it is looking for here is a collection that implements the IEnumerable interface and has the right type. This includes standard arrays and many other collection types just as with several other objects that implement this method in the .NET Framework. Let’s look at a few examples.

In this example, we’re going to take a comma delimited string entered in a TextBox and place it in our List:

Dim EmailAddresses As New List(Of String)

EmailAddresses.AddRange(txtEmailAddresses.Text.Split(","c))

In this example, we’re going to load the selected items from a ListBox:

Dim EmailAddresses As New List(Of String)
Dim AddressArray(lstEmails.SelectedItems.Count - 1) As String
lstEmails.SelectedItems.CopyTo(AddressArray, 0)
EmailAddresses.AddRange(AddressArray)

This routines involves a little trickery because we need a temporary string array to convert the Object types in the SelectedItems collection via the CopyTo method.

In addition to simply adding onto a list we can use the InsertRange method to place items after a particular location in the List, including the beginning, as seen here:

EmailAddresses.InsertRange(0, txtEmailAddresses.Text.Split(","c))

When we want to remove more than one item, we can use the RemoveRange method, where we can specify the starting position and the number to remove:

EmailAddresses.RemoveRange(3, 2)

If we want to remove items that match a particular criteria, we can use the RemoveAll method. This method uses a Predicate delegate:

EmailAddresses.RemoveAll(AddressOf ValidateEmailAddress)

...........

Public Function ValidateEmailAddress(ByVal emailAddress As String) As Boolean
    Dim pattern As String = "[a-z][a-z|0-9|]*([_][a-z|0-9]+)*([.][a-z|0-9]+([_][a-z|0-9]+)*)?@[a-z][a-z|0-9|]*\.([a-z][a-z|0-9]*(\.[a-z][a-z|0-9]*)?)$"
    Dim match As System.Text.RegularExpressions.Match = Regex.Match(emailAddress, pattern, RegexOptions.IgnoreCase)
    Return match.Success
End Function

(Note for the validate email function to work you’ll need to import System.Text.RegularExpressions)

Sorting

To sort the List we can use default comparison method or we can define our own sorting routine as a Delegate or as class that implements the IComparer interface. For the sake of brevity, I won’t include the sorting code here, but only give an example of how it’s called. If you would like an article with more detail on these sorting methods, please leave me a comment or contact me. Here are some example calls:

EmailAddresses.Sort(AddressOf SortEmails)
.......
Dim EmailSorter As New EmailComparer

EmailAddresses.Sort(EmailSorter)

Along the same lines as sorting is the Reverse method. This method, as you might guess, simply reverses the order in the list. You can also specify a starting position and length to reverse.

That’s is all for Part I. Part II will cover searching, conversions and enumeration functions available in the List object. As always, let me know if you found this overview article helpful by leaving a comment.

Share This Article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • DotNetKicks
  • DZone

2 comments August 28th, 2007

Previous Posts


Visit Me At My New Site, Programming In C#

Most Popular Articles

Highest Rated Articles

Categories

Most Recent Articles

Feeds

 Subscribe in a reader

To subscribe by e-mail
Enter your address here

Delivered by FeedBurner

VB Opportunities

Archives