Archive for August, 2007

How to Use the Action and Predicate Delegates

Delegates are an important tools for drafting your applicationsHow often do you write code to manually loop through a generic list or an array using a For…Each type loop? Have you written looping code to search for a particular property of a specific object in a list? Have you wondered if there was an easier way to select a sub-list from a generic list? Many programmers will use the manual loop method to achieve these goals. However, the Action and Predicate delegates offer you an easier and more flexible way to perform these operations.

Action

An Action is a delegate routine that works with a specified object. An Action doesn’t have a return value so it’s always declared as a Sub with a single parameter of a particular type. Pretty simple, but it may be a little confusing at first glance so we’ll work through a simple example.

We start with a generic list of products that have been passed into a routine. We need to load all of the products with a subcode specified by the user into a Listbox. Our ‘old’ way of doing this would look like this:

Public Sub LoadProductList(ByVal products As List(Of InventoryItem))
    lstProducts.Items.Clear()
    For Each item As InventoryItem In products
        If cboProductSubCode.Text = item.SubCode Then
            lstProducts.Items.Add(item)
        End If
    Next
End Sub

In the example above we manually loop through the List and load the Listbox. Now, here’s the code using an Action Delegate:

Public Sub LoadProductListBox(ByVal products As List(Of InventoryItem))
    lstProducts.Items.Clear()
    products.ForEach(AddressOf LoadListBoxItems)
End Sub

Public Sub LoadListBoxItems(ByVal item As InventoryItem)
    If cboProductSubCode.Text = item.SubCode Then
        lstProducts.Items.Add(item)
    End If
End Sub

On the surface, it doesn’t seem like that much of a savings. We now have two routines instead of one, slightly larger, routine. This could impact readability of the code in some cases although it might help with more complex routines or if multiple ForEach calls were required. If we look at the performance, the Action method is slightly faster, by a factor of about 3 to 5 percent, so there is a tiny advantage there.

Where the real power of this method comes into play is where you need to pass a particular action into the routine depending upon other conditions. For example, we might want to have a different action for different types of inventory so we would pass our preferred loading routine as an Action as seen here:

......
If OnlyNewProducts Then
    LoadProductListBox(InventoryList, New Action(Of InventoryItem)(AddressOf LoadImportedProducts))
Else
    LoadProductListBox(InventoryList, New Action(Of InventoryItem)(AddressOf LoadAllProducts))
End If
......

Public Sub LoadProductListBox(ByVal products As List(Of InventoryItem), ByVal loadingAction As Action(Of InventoryItem))
    lstProducts.Items.Clear()
    products.ForEach(loadingAction)
End Sub

As you might guess, being able to pass in a delegate Action opens up a lot of possibilities.

Predicate

A Predicate is a delegate function that determines if a specified object meets a set of criteria. Like Action it has one argument, the particular type to be evaluated, and it also returns a Boolean, indicating if the object met or did not meet the selection conditions in the routine. Predicates are used in the Find functions of generic Lists. Let’s start by defining a set of criteria we want our InventoryItem objects to meet. In this case, we’re wanting products added in the past 30 days.

Function SearchForNewProducts(ByVal item As InventoryItem) As Boolean
   If DateDiff(DateInterval.Day, item.IntroductionDate, Now) < 30 Then
       Return True
   Else
       Return False
   End If
End Function

Now we use the FindAll method to get a list of inventory items using this Predicate.

Dim NewProducts As List(Of InventoryItem) = ProductList.FindAll(AddressOf SearchForNewProducts)
.
.
.

Another operation you might want to do is to see if a member of a list has a property that meets a unique criteria or you may want to just return the first or last matching item in the list. For that, you use the Find or FindLast functions. For our example, we’re going to find the first item that wildcard matches a user TextBox entry.

.....
Dim SelectedItem As InventoryItem = NewProducts.Find(AddressOf FindByDescription)
.....

Function FindByDescription(ByVal item As InventoryItem) As Boolean
    If item.Description Like (txtItemDescription.Text & "*") Then
        Return True
    Else
        Return False
    End If
End Function

The other two Find methods are FindIndex and FindLastIndex. They return the index position of the object rather than the object itself. They also have overloads where you can specify the starting position and the number of objects in the list to search. This can be useful for incremental searches of large lists.

Another nice thing about using Predicates is that we can use the same delegate function for all of the Find functions:

.....
Dim SelectedItem As InventoryItem = NewProducts.Find(AddressOf FindByDescription)
.....
Dim SelectedItem As InventoryItem = NewProducts.FindLast(AddressOf FindByDescription)
.....
Dim SelectedItem As List(Of InventoryItem) = NewProducts.FindAll(AddressOf FindByDescription)
.....
Dim ItemIndex As Integer = ProductList.FindIndex(AddressOf FindByDescription)
.....
Dim ItemIndex As Integer = ProductList.FindLastIndex(AddressOf FindByDescription)

As you can see, this can provide a lot of flexibility in your code.

I hope this article has helped you gain a better understanding of these powerful delegate methods. If you have any questions about them or anything you would like to add, please leave 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

4 comments August 23rd, 2007

Link Round-Up for 8/23/07

Fixed a broken link todayHere are some links to interesting articles and blog posts I ran across this week on the subjects of VB.NET and software development teams.

To lead off this week, Jeff Atwood at Coding Horror wrote this piece, Leading by Example, that fits in well with my article on Marine Corps leadership, and not just because he has a picture of Gunny Hartman (R. Lee Ermey) from Full Metal Jacket in it. In the article he goes into the pitfall of being seen as an enforcer and not a leader. Good stuff.

In my article earlier this week, 10 Ways To Insure Project Failure, I mentioned the practice of using methodologies like Agile and Scrum as political cover for failed projects. To be fair, I should highlight that not everyone uses them as a way to do a CYA dance. While I’m still kind of skeptical about these processes, having seen and heard of them being misused, some organizations are using them successfully. If you want some further resources on Scrum and Agile development methods, check out this article by Billy McCafferty, Introduction to Scrum and Agile Development.

Over at dream.in.code they have free reference sheets for C++, Java, VB6, ColdFusion, and VB.NET. I recommend downloading them and tacking them up in your cubical.

On TechRepublic this week there was a lively discussion about this column by Jason Hiner, Sanity Check: Is IT still a profession worth recommending to the next generation? My opinion is that for most people entering the working world from college or making a career change IT is not a good career option for several reasons (which I may cover in depth in my own article later). Some people disagreed, some with good points other with cheesy patronizing platitudes. Anyway, it was a good discussion about IT careers and the future direction they may take.

If you want to get a heads up on what people are saying in the .NET world, check out DotNetKicks. It’s sort of like Digg for the .NET community where you can view current blog articles on .NET topics and approve of them by giving them a ‘kick’. If you like my articles, make sure you give them a kick by clicking the DotNetKicks icon on the social bookmarking bar at the bottom of the post.

That’s all the links for this week. If you know of any articles or blog posts related to VB.NET or general programming practices that you think I should take a look at, please leave me a comment or use the Contact Me page to send me a private note.

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 23rd, 2007

Introduction To VB.NET Generic Stacks

A Wedding Cake - An example of a Last-In-First-Out Stack StructureStacks are another classic data structure. Anyone who’s taken a Computer Science 101 class has probably encountered them and if you’ve done any low level coding in C++ or assembly you’ve probably written quite a few of them. However, this data structure wasn’t seen that often in classic VB or traditional BASIC programming because of the lack of pointers in the language. But, in VB.NET, we now have the Stack class and, in Framework 2.0, the strongly typed generic Stack class so you should familiarize yourself with how a stack works.

A stack is simply a Last-In-First-Out (aka LIFO) buffer where only the topmost item is visible. It’s just the opposite of the Queue structure that was covered in a previous article. A common visual metaphor used to describe a stack is a spring loaded cafeteria plate dispenser or coin holder. The standard commands for a stack are Pop, which removes and returns the top item on the stack, and Push, which places a new item at the top of the stack. Here is a simple example:

'add a url entered in a text box
UrlStack.Push(txtUrl.Text)

...

'get next url from stack and navigate to location
wbMain.Navigate(UrlStack.Pop)

In this example, we have a stack of URLs entered by the user. As the user enters a value into the textbox, we Push it onto the stack. Later in the program, we want to use the browser control to navigate to the sites so we Pop the next URL value off the stack.

What if you want to see what the topmost value is before removing it from the stack? In that case, you use the Peek function to return the value without popping it off the stack. Here’s an example:

If UrlStack.Peek().Contains("localhost") Then

In this example, we may want to perform a few other actions if the site is local before removing the URL string from the stack.

The .NET generic stack also has the standard collection management properties and methods. To get the number of items in the collection you access the Count property. To see if an item is already in the stack, you can use the Contains function. Clear is used to empty the stack. Lastly, you can use the ToArray function to move the contents of the stack to an array of the same type. Here are some examples:

If UrlStack.Count > 0 Then
    'do something with the stack
End If

If Not UrlStack.Contains(txtUrl.Text) Then
    UrlStack.Push(txtUrl.Text)
End If

UrlStack.Clear

Dim UrlList() As String = UrlStack.ToArray()

Note that it is a good idea to check the Count property of the stack before you Pop or Peek since it will generate an InvalidOperationException if it is empty. Also, while you don’t have to worry about stack overflows like you do in C++ you should be mindful of how much memory your stack is using, particularly if you use it for large custom searches and sorts.

How can you use stacks in your code?

A common use for stacks are in complex searches. If you see your search code headed in a brute force, linear, model, step back and investigate how your code might benefit from using stacks. You can Google up many examples of how to do this or read Wikipedia articles on the various search algorithms. While they probably won’t be in VB.NET, you can probably extract the logic and use it.

Games are another area where using stacks can be quite helpful. For example, you’ll find many game map or maze building programs use stacks extensively.

If you have any questions about using Generic Stacks or if you have suggestions or examples on how you use them, please leave 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

Add comment August 22nd, 2007

Introduction to VB.NET Generic Queues

Elf with a Queue of GiftsQueues are one of the common classic data structures found in computer science. A queue is simply a First-In-First-Out (aka FIFO) buffer where new items are added to the end of the list and the item at the front of the list is processed first. Implementing one in VB hasn’t always been easy due to the lack of pointers. While there were some ways to work around this, the programming could get messy and difficult to understand. However, the Queue collection type was introduced in the original .NET Framework and now, in the .NET Framework 2.0, we now have the generic Queue class to make it a breeze to implement.

As with other .NET Generic Collection classes, the queue is a type-safe collection. This means that you must define the type of object that is to be queued and only objects of that type can be placed in the queue. Here are a few examples:

Dim NameQueue As Queue(Of String)

Dim MailQueue As Queue(Of Net.Mail.MailMessage)

Dim OrderQueue As Queue(Of OrderDetailItems)

The basic operations of a queue are enqueue and dequeue. Enqueue places a new item at the end of the queue while Dequeue removes the first item in the queue from the list and returns it to the caller. The queue automatically expands to accomidate new members. Remember that if the queue is empty that the Dequeue function will return an InvalidOperationException. Here are some simple examples:

NameQueue.Enqueue(CurrentName)

Do While MailQueue.Count > 0
    SendMail(MailQueue.Dequeue)
Loop

If you wanted to view the next item in the queue without removing it, you can use the Peek function as seen in this example:

If IsSignedUp(MailQueue.Peek.To) Then
    SendMarketingEmail(MailQueue.Dequeue)
Else
    SendSignUpEmail(MailQueue.Dequeue)
End If

To further manage the Queue there is the Clear command that removes all of the contents of the Queue and the Count property to get the current number of items in the queue. There is also the Contains function that you can use to find out if a particular item is already in the queue. For example:

If Not FileNameQueue.Contains(NewFileName) Then
    FileNameQueue.Enqueue(NewFileName)
End If

One feature that you might find helpful at times is the ability to copy the Queue to an Array as seen here:

Dim MailList() As Net.Mail.MailMessage = MailQueue.ToArray()

That covers the basics of the .NET Generic Queue but maybe you’re wondering when you should use a queue?

I’ve found them particularly useful for situations where I had longer operations to process, such as parsing or converting a large datafile. For example, if I had files arriving in a FTP folder I would use FileSystemWatcher to detect the files as they arrived and place them in the queue. Then, at some point, such as every 30 minutes, the current items in the queue would be processed in the order they arrived and a new queue would be started.

Another example would be having a central order system prepare a queue of items for a remote fulfillment centers. The fulfillment center system would retrieve a serialized queue of orders via a web service from the order location’s web site and then work through the order objects within it.

If you have any questions about using Generic Queues or if you have suggestions or examples on how you use them, please leave 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 21st, 2007

Exploring the System.IO.Path Namespace - Part II

exploring System.IO.PathIn this second part of my series on the System.IO.Path we will be taking a look at some additional functions in this namespace and see how they can be applied to your programs. You can read Part I of this series here: Exploring the System.IO.Path namespace - Part I.
.
.
.
.
GetRandomFileName

This interestingly named function returns a random string that you can use as either a folder name or a file name.

Dim NewFileName As String = IO.Path.GetRandomFileName()

NewFileName Example Value: "udhusxh3.0gh"

Unlike the Temp file functions, this function doesn’t create a file on the disk itself, it only provides you with a string of correctly formatted random characters. It is useful for creating your own random files but it is usually best from a security and rights standpoint to use the temp file creation functions instead.

GetTempFileName

As mentioned above, this function creates a new temp file on the disk in the appropriate temp file area for the user and returns the full file/path string to this newly created file.

Dim NewFileName As String = IO.Path.GetTempFileName()

NewFileName Example Value: "C:\Documents and Settings\username\Local Settings\Temp\tmp93D.tmp"
.
.
.

Using this method is preferred in situations where you may not have full disk access, such as in a ClickOnce deployment or deployment to secured desktops, because the temp area will be available and writable in most cases. It is important to remember to clean up after yourself if you this method. You don’t want to leave orphaned temp files behind.

GetTempPath

This function returns the name of the current user’s temp folder for the application as seen here.

Dim TempPath As String = IO.Path.GetTempPath()

TempPath Example Value: "C:\Documents and Settings\username\Local Settings\Temp\"
.
.
.

Usually the result will look like the path shown in the example above. However, you can’t depend on this and hard code this value. It is possible that the temp file location could change with a system configuration change. Also, if ClickOnce deployment is used, the temp file area may be in the ’sandbox’ and not the usual location. Using this function to get the location always returns reliable results for the current configuration.

HasExtension

This function checks a file/path string to see if it has an extension or not. Basically, it searches the specified string for a final period that doesn’t have any other file punctuation after it and has one or more other characters after it.

If IO.Path.HasExtension(NewFileName) Then

This function is moderately useful for checking if a string is only a path or a file name or path/file name combo. Note that it doesn’t indicate if the file exists on disk or not. It only tests the string.

IsPathRooted

This is another testing function that will tell you if the specified string contains a valid path or is just a file name. For example, if the string in question had only the file name but no path information, this function call would return False. However, it there was a valid path string before the file name, True would be returned.

If IO.Path.IsPathRooted(NewFileName) Then

Note that this function does not check for the exisistance of a path or file on the disk, it only checks the validity of the string itself. When combined with HasExtension it is quite useful in determining if a string can be safely used to construct a file.

File/Path Character Functions and Properties

Lastly, this namespace contains some functions and properties that can be helpful if you’re dealing with file systems outside of Windows, such as GetInvalidPathChars and GetInvalidFileNameChars. These probably won’t come into play much for you if you’re only working with Visual Studio in Windows. However, should you venture onto using .NET on other platforms, you might find them useful.

I hope these two articles were a good review of the System.IO.Path functions for you. Because the .NET Framework is so large it’s often easy to overlook areas of it. I know I found doing this review helpful to me and I hope you did too. If you have a question or thoughts on this namespace, please feel free to leave 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

Add comment August 20th, 2007

Next Posts Previous Posts


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