To comment or not to comment

Introduction

Anyone that has ever taken a programming class or read a beginners book on the subject know how important it is to write comments in your code. But is that really true? In this post I’m going to discuss/question the common practice of writing comments in your code.

Bad comments

A couple of weeks ago I was contacted by an old friend of mine that runs a construction company. They have an old custom system that they’ve had since the mid or late ’90s sometime. He wanted some slight modifications made to this system, but the consultant business that created it apparently disappeared sometime during the dot-com death era. So he wondered if I could have a look at it and come up with an estimation of how much work it would require to do these customizations he needed.

Since he had all the source code – and because I’m such a nice guy – I asked him to e-mail the source over to me, which he did. When I opened up the old project (which was written in Visual C++ 6.0) the first thing I saw in the main file was this (the name of the developer and company have been changed to protect the guilty).

/***********************************************************************************
*
* File name   : CGMain.cpp
* Developed by: John Doe
* Company     : Former Dot Com Inc
* E-mail      : john.doe@nowheretobefound.com
* Date        : 1997-03-21
* Requirements: None
*
*-----------------------------------------------------------------------------------
* Version history
*-----------------------------------------------------------------------------------
*
* 1.0.0 Initial release
*       1997-03-21
* 1.0.1 Minor bug fixes
*       1997-03-24
* 1.0.2 Added 2 functions: AccViewF() and AccViewT()
*       Reason: The customer needed to store the AccView creator and delivery
*       1997-04-03
* 1.0.3 Minor bug fix
*       1997-04-05
* 1.0.3 .... This goes on and on ...
*  ...
*  ...
* 1.2.7 Minor fix
*       1998-04-02
*
***********************************************************************************/

I can assure you that the list was lot longer than what I posted here. What is this good for? Why does a file need a comment header that tells me the name of the file? I already know which file I opened. Do I really care who wrote it? I don’t know that person and the contact information isn’t correct anyway. Could somebody explain to me why you would need a version history typed into the file? Ever heard of source control systems? Those are made to keep track of different versions of your file. The above comment doesn’t bring any useful information my way, or to my friend who isn’t a developer and because of that never even looked at the source code. All it did was made me scroll down a page or two before I got to the actual code.

I can understand that a company that sells class libraries and components with accompanied source code might want to add a (hopefully short) copyright notice on top of each file, but other than that there is really no reason why you want to have a commented header in your file.

When to add comments and when not to

In .Net there is one type of comments I always recommend people to use and that is XML comments. Those are great when they are added to methods and properties of a class library. A library, I might add, that you probably never open up the source code for, at least not if it comes from a third party. The XML comments aren’t meant to be read by humans, they are read by the compiler and shows valuable (hopefully) information in IntelliSense tooltips. Other helpful comments are JavaDoc and PyDoc comments used respectively in Java and Python to create documentation.

I remember once reading a blog post by Jeff Atwood about this very subject, please hold on while I Google it for you……. ah, here it is. Jeff also wrote a long rant about header comments, much like the one above. However in his post he, more or less, said that you shouldn’t use comments at all, which I don’t fully agree with him on. But he has a very important point which I think is also an excellent advice, always aim to write, or refactor, your code so it doesn’t need any comments. With that I (and I think also Jeff, even though I can’t really speak for him) mean that you should always give your methods a very descriptive name, keep them short and to the point.

But unlike Jeff I still think it can be valuable to sometimes stick in a short comment that explains what the code is doing. However you must remember that the comment is then as important as the source code. If you refactor or change the source it is important that you also update the comment. Nothing is as useless as a comment that isn’t valid anymore.

A while back I saw the following comment in the code behind file of an ASP.Net page.

'TODO: The following code is very resource-intensive and
'      should be refactored.

The page that contained this comment had been in the web application in question for years. I looked at the code and couldn’t figure out what it was that was so resource-intensive. I stepped through it, and analyzed it very carefully without finding anything special. So somebody must at some point have done what the comment said, but without removing the comment, which made me waste my time to analyze perfectly working code for no reason at all. Here’s another comment from the same project.

'This is probably not a good idea, 
'and should be changed but I’ll leave it for now.

Excuse me while I scream and swear… (this text has been censored). What is it that isn’t such a good idea? How am I to know how the original developer was thinking when he wrote the above comment? Did he have a brilliant idea how the code could be refactored but was to lazy to do it now? Has he refactored the code but yet again forgot to remove the comment?

The point here is to never write comments that only make sense to yourself. Code is written once and read many times. Much of the code you write today are legacy tomorrow when you aren’t around anymore and some other poor sob have to update it. Always edit or remove comments when you edit the source.

At this point it probably sounds as if I think you shouldn’t write any comments at all with the exception of XML comments, but that is not the case. As Joel Spolsky have said: Code is easier to write than to read. That is so true. How often haven’t you looked back at some code you wrote just a couple of months ago and wondered: How was I thinking here… Not that you weren’t thinking when you wrote it, the code is probably just fine, but at the moment you can’t remember the flow of the source. When you develop you are in the middle of it and probably know exactly why you should call that particular method from this particular place, but a few weeks later (after you’ve been working on something very different) when you revisit your older code you just can’t remember that flow. So it takes a while before you are up to speed with it again. Now, what if that isn’t you that revisit your old code? Somebody else that thinks in a different manner than you will have a much harder time to get the flow before he/she can be productive with your source. This is the main reason why developers want to work on new projects all the time. We usually don’t like to work with old legacy code, especially old code we haven’t written ourselves.

In those cases a few well placed comments might help a lot. Just keep remembering that you need to refactor the comments just as much as you need to refactor the source code.

End words

There are one type of comments I do enjoy to read, and that is your comments on my blog posts. :)

Have fun!

Copy and Paste programming – A bad habit

Introduction

I usually stay away from religious discussions when it comes to programming habits and technology choices simply because they don’t usually make any sense at all and are most often just based on emotions. Arguing if VB.Net is better or worse than C# is just nonsense in my book since the differences between them are minor. They both target the same platforms, and use the same framework, of course there are differences but none of them are so great that you would say that this is a much better language. I personally think that XML literals in VB are great but that alone doesn’t make VB a better language. It is just easier to handle XML in VB, so if you do a lot of that VB is a better choice for that particular purpose. I also like the ease with which C# handles iterators, but again that doesn’t make C# a better language, it just make that particular code part easier.

imageAnother discussion I often see on the Web is if the Java J2EE framework is better or worse than the .Net framework. Again this just stir up emotions, if you’re a Java programmer you would of course say that Java is better than .Net and the other way around. It’s not true though… Java is not better than .Net and neither is .Net better than Java. It all comes down to which platform you’re targeting and what the requirements are for the project at hand.

Is an axe better than a saw? No, they are both exceptionally bad tools – if you’re trying to nail two pieces of wood together, that is. In that case you should use a hammer and not an axe and definitely not a saw.

Having said that, this post will still be a rant about a thing that really grinds my gears, copy and paste programming.

Why you should ban Copy and Paste 

I want to start by making one thing very clear, I do not think it’s a bad habit to copy a great piece of code you find somewhere on the web and then paste it into your project. As long as you test the code and perhaps refactor it to fit your naming convention then that’s just fine. What I talk about is the habit of copying and pasting the same code all around a project or even between different projects. Come on! If you’re reading this blog there’s a big chance that you’re a .Net developer and as such you use a modern OOP language. The whole purpose of object oriented programming is to create classes for code reuse and to preserve encapsulation. Even if you’re using a structured programming language you can still refactor your code so that you don’t have to repeat the same thing over and over.

Even though older code might be well used and therefore perhaps less buggy doesn’t mean that it will stay that way. Business rules changes and if you need to change how a particular piece of code works you should only need to do that in one place. Also, if the code does contain a bug, you have just introduced the same bug in another place. The next time you feel the urge to copy some code think again and cut it instead. Cutting the code and pasting it elsewhere means you’re refactoring your code and refactoring (to paraphrase Martha Stewart) is a good thing. Cut the code, paste it into a new method and call that method from the place the code used to reside.

If you’re working on a WPF or Silverlight project you don’t even have to copy and paste common XAML code, use a ResourceDictionary instead. But that’s design code, it’s much more important to not copy and paste business logic or data access layer code to different places.

Conclusion

What do you mean conclusion?
Haven’t you paid attention?
Stop copy and paste code! :)

Have fun!
kick it on DotNetKicks.com

Develop for Windows 7

Have you any plans on starting to develop applications for Windows 7 yet?

The Windows API Code Pack can be used to access some of the new features in Win7, but also some existing features in older version of the Windows OS. The team at Microsoft that are behind the code pack have just updated all the sample code so they now come in both VB as well as in C#, and they did a very good job with it too. So go have a look, it’s pretty neat.

Have fun.

At your service (part II) – ASMX Web Service vs WCF

Introduction

Last time I demonstrated how to develop a Windows Communication Foundation (WCF) service. This time we’re going to look at the differences between a ASP.Net WebService and a WCF service. The biggest difference between them is probably that a WebService only can be activated via HTTP and they are tightly coupled with ASP.Net HTTP pipeline. A WCF service on the other hand can be bound to a large variety of network protocols. It also doesn’t require that it is hosted on a web server, it can be hosted in a console application, in a Windows Forms app, or in a WPF application. However WCF does have an ASP.Net compatibility mode setting to enable WCF services to be configured like a web service and also mimic their behavior.

Data representation

A WebService relies on the XmlSerializer to serialize types into XML and back to a .Net type. The following is a list of the things XmlSerializer can serialize to and from XML.

  • Only the public properties (or fields) of an object.
  • Collections can be serialized only if the implement the IEnumerable or ICollection interfaces.
  • Classes that implements the IDictionary interface, such as Hashtable, cannot be serialized into XML.
  • You can use attributes from the System.Xml.Serialization namespace on your own classes and members to control how instances of that class will be serialized.
  • You can also generate classes that can be serialized into XML from definitions of the types in XML Schema using the xsd.exe command line tool.

Point 4 and 5 describes how you can define complex types (classes) that can be serialized to and from XML.

In WCF you would also usually begin with the definition of complex types which is done adding the DataContractAttribute and the DataMemberAttribute to the class and its members, as described in my earlier post. The DataContractAttribute can be used on classes or structures and the DataMemberAttribute on properties and/or fields, which can be either private or public.

A few important differences between the DataContractSerializer and the XmlSerializer are:

  • The XmlSerializer serialize all public fields and properties, while you have better control using the DataContractSerializer.
  • The DataContractSerializer has better performance over XmlSerializer.
  • The DataContractSerializer can serialize Hashtables.

Service Development

To develop a WebService you would normally decorate a class with the WebServiceAttribute and each method with the WebMethodAttribute. This is however not an optimal solution since it does not constitute a contract for the operations performed by the service. ASP.Net 2.0 tried to rectify that by allowing you to use those attributes on an interface as well. That is the preferred method of doing it since the service contract can be reused with various classes that can implement that interface.

A WCF service requires you to create a contract, since the ServiceContractAttribute only can be used on an interface. So a WebService allows you to constitute a contract but doesn’t enforce it while a WCF service do.

A WebService only incorpartes BasicHttpBinding while a WCF service can use a wide range of bindings, such as WSHttpBinding, NetTcpBinding, NetNamedPipeBinding, amongst others.

Hosting the service 

ASP.Net web services are hosted on a Web Server. A WCF service can be hosted on a Web Server but can just as well be hosted by a Console- or Windows Forms application.

Conclusion

I don’t want to make any conclusions about which technique is the best to use, because that depends on the specification. A WebService is usually easier to develop but are somewhat limited. A WCF service is more versatile but can be harder to develop. To make a true comparison you should really compare the two techniques if you want to host the service on a Web Server, such as IIS, since if you want to use another host you can’t use an ASP.Net WebService. I just leave the judgment up to you.

Have fun!

At your service (part I) – WCF tutorial in VB

Introduction

In this post I’m going to do a tutorial on Windows Communication Foundation, WCF. This tutorial is divided in 4 steps:

  1. Defining the WCF data and service contracts.
  2. Implementing the WCF service contract.
  3. Creating the service-host application.
  4. Create a client application that uses the service.

So without further ado, let’s get busy.

Here is where we are getting busy

We’re going to implement our WCF server as a simple console application so start Visual Studio and create a new Console project. But for now we just leave the Sub Main() empty, since we implement the server in step 3. We also need to add a couple of references, first of all we need to add a reference to the System.ServiceModel.dll, right click on the project node in the Solution Explorer and click Add>Reference and scroll down the list until you find it. We also need to add a reference to the System.Runtime.Serialization.dll, so repeat the earlier step to add that as well.

Before we start with the WCF specific details we’re going to create a Data Access Layer (a DAL) which our service will work against to retrieve data. For the purpose of this article I’ve made a very simple class that can return a list of persons, or a single person. This could be customer information or an employment roll or whatever. In this sample I’ve hardcoded a list of persons, in a real word application you would retrieve this data from a database.

Public Class DataAccess
  Private Shared _list As List(Of Person)
  Private Shared Function GetPersonList() As List(Of Person)
    If _list Is Nothing Then
      _list = New List(Of Person)
      With _list
        .Add(New Person(1, "Homer", "Simpson"))
        .Add(New Person(2, "Marge", "Simpson"))
        .Add(New Person(3, "Bart", "Simpson"))
        .Add(New Person(4, "Lisa", "Simpson"))
        .Add(New Person(5, "Maggie", "Simpson"))
      End With
    End If
    Return _list
  End Function

  Public Shared Function GetPerson(ByVal id As Integer) As Person
    Return (From p In GetPersonList() Where p.ID = id).FirstOrDefault
  End Function

  Public Shared Function GetPersons() As List(Of Person)
    Return GetPersonList()
  End Function
End Class

As you can see the methods returns either a List(Of Person) or a single Person object. We will create the Person class in the next step.

Defining the WCF data and service contracts

We need to create a data contract for each object a WCF service can return, we also need to mark each property that is returned as a DataMember. We do that by adding attributes to our class and its members. Add a new class to the project, make sure you import the System.ServiceModel and the System.Runtime.Serialization namespaces, that we added a reference to earlier, and add the following code to the class.

Imports System.ServiceModel
Imports System.Runtime.Serialization

<DataContract()> _
Public Class Person
  Private _id As Integer
  <DataMember()> _
  Public Property ID() As Integer
    Get
      Return _id
    End Get
    Set(ByVal value As Integer)
      _id = value
    End Set
  End Property

  Private _firstName As String
  <DataMember()> _
  Public Property FirstName() As String
    Get
      Return _firstName
    End Get
    Set(ByVal value As String)
      _firstName = value
    End Set
  End Property

  Private _lastName As String
  <DataMember()> _
  Public Property LastName() As String
    Get
      Return _lastName
    End Get
    Set(ByVal value As String)
      _lastName = value
    End Set
  End Property

  Public Sub New(ByVal id As Integer, ByVal firstName As String, ByVal lastName As String)
    _id = id
    _firstName = firstName
    _lastName = lastName
  End Sub
End Class

The next step is to create the service contract for our WCF service. This contract defines what kind of operations our service provides and are defined as interfaces.

<ServiceContract(Namespace:="http://demo.wcf.samples")> _
Public Interface IPerson
  <OperationContract()> _
  Function GetPerson(ByVal id As Integer) As Person
  <OperationContract()> _
  Function GetPersons() As List(Of Person)
End Interface

Notice that the interface is decorated with a ServiceContractAttribute, I also changed its namespace, specifying the namespace is a best practice to prevent the default namespace of “http://tempuri.org” being used. Each operation that our service provides must be marked with the OperationContractAttribute, which you can see that I used on the two methods.

OK, now we have our contracts set up so we now need to implement them which we do next.

Implementing the WCF service contract

Since the contract and the service interface have already been designed, creating the service is straightforward and only requires that the interface is implemented.

Public Class PersonService
  Implements IPerson

  Public Function GetPerson(ByVal id As Integer) As Person _
Implements IPerson.GetPerson Return DataAccess.GetPerson(id) End Function Public Function GetPersons() As List(Of Person) _
Implements IPerson.GetPersons Return DataAccess.GetPersons() End Function End Class

As you can see I simply call the methods in the DataAccess class, that we defined in the introduction, in the implementation of the two methods.

That’s it. Our service is all done. But to be able to use it from a client application later we need to create a service-host application, which will host our service objects. That will be our actual server application and we’ll start creating that next.

Creating the service-host application

As I mentioned in the introduction, we will implement our service-host as a simple console application. So open the module with the Sub Main() definition and import the System.ServiceModel and the System.ServiceModel.Description namespaces. The latter of the namespaces is needed to describe the behavior of the metadata. In our case we will allow a client to get the data via a HTTP GET request.

The first thing we need to do is to configure a base address for the service. We do that by creating a new URI that specifies the address, port number, and the path of our service. We can use any IP port number that is usually not occupied, in this example I will use port 8240.

Dim uri = New Uri("http://localhost:8240/demo/wcf/samples")

As the path of the service I picked the same as I did for the namespace of the service contract we created earlier (which was “http://demo.wcf.samples”).

Next we need to create a ServiceHost reference, to which we must pass the type that implements our service contract and the base address that we just specified.

Dim host As New ServiceHost(GetType(PersonService), uri)

Now that we have our ServiceHost object we need to add an endpoint that exposes the service. To do this, you must specify the type of the contract the endpoint is exposing, a binding, and the address of the endpoint. The contract is our interface, and in this demo we will be using the WSHTTPBinding as the binding, and for the address we simply use the string “PersonService”.

A WCF service can use almost any kind of binding, you can use http binding, tcp binding and so on.

We will also need to enable Metadata exchange, to do that we add a service metadata behavior, as I already mentioned we will allow a client to get data from the service via a HTTP GET request. When this is done all we have to do is to open our host and wait for client requests.

Try
  host.AddServiceEndpoint(GetType(IPerson), New WSHttpBinding, "PersonService")
  Dim behavior As New ServiceMetadataBehavior()
  behavior.HttpGetEnabled = True
  host.Description.Behaviors.Add(behavior)

  host.Open()
  Console.WriteLine("The service has been started.")
  Console.WriteLine("Press the ENTER key to terminate service.")
  Console.WriteLine()
  Console.ReadLine()
  host.Close()
Catch ex As CommunicationException
  Console.WriteLine("Error: {0}", ex.Message)
  host.Abort()
End Try

You can now run the application. Not much will happen though, a console window will be created and the message that the service is started is shown. What we need to do now is to create a client application that can use the service. We’ll do that in the next section.

Create a client application that uses the service

Start by launching a new instance of Visual Studio, and create a new Console Application project. Add a reference to the System.ServiceModel.dll.

The first thing we need to do is to get the meta data of the service, and create the proxy code. You can use the SvcUtil.exe command line tool to do so, but there is an easier way. We can let Visual Studio do this for us by adding a Service Reference. To do this we first must make sure our service is running. So switch back to the previous instance of Visual Studio and start the project. Now switch back to this instance of Visual Studio and right click on the project node in the Solution Explorer and select “Add Service Reference” in the context menu. In the dialog that pops up we type in the URI we specified for our service endpoint in the previous section (http://localhost:8240/demo/wcf/samples) and click on the Go button. You should get the result you can see in the image below.

image

Click on the OK button and wait a few seconds while Visual Studio creates the proxy code for you.

Our proxy client will get the name PersonClient() which we need to create an instance of to be able to call the methods our service exposes.

Public Sub Main()
  Dim client As New ServiceReference1.PersonClient()
  Dim pers As ServiceReference1.Person = client.GetPerson(1)
  If Not pers Is Nothing Then
    Console.WriteLine("Person with ID=1 is {0} {1}", _
                      pers.FirstName, pers.LastName)
  End If
  Console.WriteLine("Person list")
      
  For Each p In client.GetPersons()
    Console.WriteLine("{0}: {1} {2}", _
                      p.ID, p.FirstName, p.LastName)
  Next
  Console.ReadLine()
End Sub

Make sure the service is running before running this code.

Conclusion

That’s all the steps that is needed to create a simple WCF service. It does require more code than an ASP.Net Web Service, in which you basically slap a WebMethodAttribute() to a method and your done, but I like the fact that WCF services encourage developers to use the contract-first principles. Next time, in part 2 of this “At your Service” series, I will do a comparison of an ASP.Net Web Service contra a WCF Service. Until then:

Have fun!

Debugging a Windows Service

Introduction

In my last article I showed a simple example of how to create a Windows Service using VB. This time we’re going to have a look at how to debug the service from Visual Studio.

Since a service must run from the context of the Service Control Manager you can’t normally debug it in the same manner as you would any other project type. Normally you would need to build the project, install it using the InstallUtil.exe command line tool, and attach a debugger to the process while it’s running. Another approach is to create a separate project (console application) and call your main code from there.

Neither of these are an ideal way of doing the debugging so I’m going to show an alternative method, which you also can use to run your service from the command line, just like any other application.

Converting the service into a command line tool

When you create a Windows Service project in Visual Studio 2008, you get a ServiceBase designer to which you add controls and your code to. Normally you would, at the very least, override the OnLoad() and the OnStop() methods. But the designer also creates a shared (static) Main() method for you, which is the real starting point of the service. To be able to see that you need to open the designer generated code file. In VB this file is normally hidden, so you need to press the Show all files button in the Solution Explorer.

image

The Main() method looks like this (with some comments removed).

<MTAThread()> _
<System.Diagnostics.DebuggerNonUserCode()> _
Public Shared Sub Main()
  Dim ServicesToRun() As System.ServiceProcess.ServiceBase
  ServicesToRun = _
New System.ServiceProcess.ServiceBase() {New FileWatcherService} System.ServiceProcess.ServiceBase.Run(ServicesToRun) End Sub

A Main() method can receive arguments from the command line, you just have to add a string array as a parameter of the method. The whole idea is that if a specific command line switch is passed to the executable it should not act as a Windows Service but instead run as any other EXE file. So I rewrote the above method to this:

' The main entry point for the process
<MTAThread()> _
<System.Diagnostics.DebuggerNonUserCode()> _
Public Shared Sub Main(ByVal args() As String)
  Dim runAsService As Boolean = True
  For Each arg As String In args
    Select Case arg.ToLower
      Case "/c", "-c"
        runAsService = False
    End Select
  Next
  If runAsService Then
    Dim ServicesToRun() As System.ServiceProcess.ServiceBase
    ServicesToRun = _
New System.ServiceProcess.ServiceBase() {New FileWatcherService} System.ServiceProcess.ServiceBase.Run(ServicesToRun) Else Dim service As New FileWatcherService service.CommandLineExecution = True service.OnStart(New String() {""}) End If End Sub

If the /c or –c switch is found among the command line parameters then it will start as a regular program. As you can see, if the switch is found, instead of creating an instance of the ServiceBase class I create an instance of my service class directly and call its OnStart() method. I also added a CommandLineExecution property to the class so I can keep track of how it is supposed to be executed. If you need to set a breakpoint or step through the Main() method you need to remove the DebuggerNonUserCode attribute, otherwise Visual Studio will just run through this method without stopping (this is what you normally would want to do with designer created code).

Now I also needed to make some changes to the OnStart() method.

Protected Overrides Sub OnStart(ByVal args() As String)
  Dim handle As IntPtr = Me.ServiceHandle
  If Not Me.CommandLineExecution Then
    _serviceStatus.currentState = Fix(State.SERVICE_START_PENDING)
    SetServiceStatus(handle, _serviceStatus)
  End If
  Dim logMessage As String = String.Empty
  If Not ReadSettings(logMessage) Then
    WriteLogMessage(logMessage, EventLogEntryType.Error)
    _serviceStatus.currentState = Fix(State.SERVICE_STOPPED)
    If Not Me.CommandLineExecution Then
      SetServiceStatus(handle, _serviceStatus)
    End If
  Else
    If Not String.IsNullOrEmpty(logMessage) Then
      WriteLogMessage(logMessage, EventLogEntryType.Information)
    End If
    'Start the file watching...
    With FileSystemWatcher1
      .BeginInit()
      .Filter = _fileMask
      .IncludeSubdirectories = _includeSubFolders
      .Path = _folderName
      .EnableRaisingEvents = True
      .EndInit()
      If Not Me.CommandLineExecution Then
        _serviceStatus.currentState = Fix(State.SERVICE_RUNNING)
        SetServiceStatus(handle, _serviceStatus)
      Else
        Threading.Thread.Sleep(Threading.Timeout.Infinite)
      End If
    End With
  End If
End Sub

If the CommandLineExecution property is set to True I skip all the calls to the SetServiceStatus() Win32 API function. I also end the method by letting the current thread sleep for infinity, if I didn’t do that the program would just exit when it reached the end of the method.

I also made a slight change to the WriteLogMessage() method, if the application isn’t running as a service there is no reason to do the logging to the Event Viewer. Instead it simply shows a message box.

Private Sub WriteLogMessage(ByVal message As String, _
ByVal type As EventLogEntryType) If Not Me.CommandLineExecution Then If Not EventLog.SourceExists("File Observer") Then EventLog.CreateEventSource("File Observer", "File Observer Log") End If Dim log As New EventLog() log.Source = "File Observer" log.WriteEntry(message, type) Else MsgBox(String.Format("{0}: {1}", type.ToString, message)) End If End Sub

Debug the service

To be able to run this service as a regular application from Visual Studio you must pass the command line switch /c. You can specify command line arguments on the Debug tab of the project properties dialog.

image

Conclusion

In this post I showed you how to turn a Windows Service into a regular executable using a command line switch to allow you to debug it from Visual Studio. Of course, instead of a command line switch you could instead just check if the application is in debug or release mode. But I wanted to be able to run the service as a regular application even after it was compiled and deployed in release mode.

Have fun!

Creating a Windows Service using VB.Net

Introduction

Yesterday I got a call from my brother, or actually he sent me a message over MSN. He wanted to know if I could help him create a program with a very specific requirement. Where he works they have a system that creates a lock file when you enter a new journal into the system. However because of a bug (?) in that system, this file is not always deleted after the journal have been entered. If this file is not removed, no more journals can be entered and the system runs amok.

So my brother wanted a program that could monitor a folder for this file, if it’s not removed within a specified time, say 1 minute, an e-mail notification is supposed to be sent. Since this program was supposed to run on the server, it needed to be a Windows Service.

Creating a Windows Service

Creating a Windows Service might not be something you do on a daily bases, during my career I’ve only made 3 or 4 of them, and this one was the very first I’ve created using .Net. Developing a Windows Service used to be pretty darn difficult, but not any more. As it turned out it’s fairly easy these days.

You start by selecting the Windows Service project type in the New Project dialog box in Visual Studio.

image

Doing that will give you a ServiceBase designer on which you can drop your controls, but since a Service normally don’t interact with the desktop, since it’s supposed to be running even if nobody is logged in, you shouldn’t use input controls such as text boxes or buttons. Using a Timer is a normal way of handling the work the service should do, but in my case I only needed a FileSystemWatcher, so I just dropped that on to the designer surface. The designer also have a handful of properties, many of which are named Can… such as CanPauseAndContinue and CanStop. If you set the CanPauseAndContinue property to True you can override the OnPaus and OnContinue methods. In my case I wasn’t interested in that but I did want an administrator to be able to stop the service so I left the CanStop property as True. If you, like me, leave the properties with their default settings you will have to override the OnStart and OnStop methods and I will cover that shortly.

I needed a way to store settings for this service, such as the time it would wait before sending an e-mail, the folder and file it was going to watch, and various SMTP and mail settings, such as the subject and the body text. To keep it as simple as possible I decided to add an App.Config file. To do that just right click on the project in the solution explorer and select Add > New Item, in the context menu. Find the Application Configuration template and click the Add button. Note, leave the name as app.config Visual Studio will automatically rename this file and copy it to the Bin folder when you build the project. To be able to read the config file you need to add a reference to System.Configuration.

I will not go into the details of using an app.config file but in short you need to add an <appSettings> section under the <configuration> node under which you add your own settings.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="emailSubject" value="Can somebody remove this file please?" />
    <!-- 
      more settings go here…
    --> 

You can then read these values using the ConfigurationManager.AppSettings() method (this requires that you have imported the System.Configuration namespace which we set a reference to earlier).

In my service I added a private method which I simply called ReadSettings. I will not show you all of that code since it’s mainly boiler plate, but a part of it looks like this:

Private Function ReadSettings(ByRef logMessage As String) As Boolean
  Dim emailRecipients As String()
  _eMailTo = New List(Of String)
  Try
    emailRecipients = ConfigurationManager.AppSettings("emailTo").Split(";"c)
  Catch ex As Exception
    logMessage = _
"No e-mail recipients with valid e-mails found, " & _
"
edit ""emailTo"" in the config file."
Return False End Try For Each email In emailRecipients email = email.Trim If Not String.IsNullOrEmpty(email) AndAlso IsValidEmail(email) Then _eMailTo.Add(email) End If Next If _eMailTo.Count = 0 Then logMessage = "No e-mail recipients with valid e-mails found." Return False End If Try _subject = ConfigurationManager.AppSettings("emailSubject") Catch ex As Exception logMessage = "No e-mail subject found" _subject = String.Empty End Try 'read the rest of the settings Return True End Function

This method takes a parameter, logMessage, by reference. In some cases, for example with the e-mail subject, it is allowed to leave that out of the config file and the application will simply send the e-mail without a subject. Other settings, like the address or addresses to send the e-mail to is required. The ReadSettings method will return False if some required setting was not found, or in the wrong format. The actual writing to the log is done by the OnStart method, or rather it’s done by another small helper method that is called by the OnStart method.

Private Sub WriteLogMessage(ByVal message As String, _
ByVal type As EventLogEntryType) If Not EventLog.SourceExists("File Observer") Then EventLog.CreateEventSource("File Observer", "File Observer Log") End If Dim log As New EventLog() log.Source = "File Observer" log.WriteEntry(message, type) End Sub

I put all validation rules in the ReadSettings() method so that when it’s time to send the e-mail, I know that I have e-mail addresses that are valid (or rather, that they have a valid form, not that I can check if the address itself really exists), and that the SMTP IP port is set to a valid integer and so on.

The OnStart() and OnEnd() methods

Even though you can override the constructor of the ServiceBase control, you shouldn’t really put initialization code there. This is because if the service is stopped and then restarted the constructor is not called again, but the OnStart() method is. So initialization should go into that method.

In my very specific case, I used a FileSystemWatcher to monitor the specified folder for the creation of the specified file. If the ReadSettings() method returned True I started monitoring the folder. If not I needed a way to stop the service from starting and write an error message to the event viewer. Unfortunately the OnStart() method does not have a way of signaling an error, so what you need to do is to call the SetServiceStatus() function which is a Win32 API function. Import the System.Runtime.InteropServices namespace and add the following code to your class.

<StructLayout(LayoutKind.Sequential)> _
Public Structure SERVICE_STATUS
  Public serviceType As Integer
  Public currentState As Integer
  Public controlsAccepted As Integer
  Public win32ExitCode As Integer
  Public serviceSpecificExitCode As Integer
  Public checkPoint As Integer
  Public waitHint As Integer
End Structure

Public Enum State
  SERVICE_STOPPED = &H1
  SERVICE_START_PENDING = &H2
  SERVICE_STOP_PENDING = &H3
  SERVICE_RUNNING = &H4
  SERVICE_CONTINUE_PENDING = &H5
  SERVICE_PAUSE_PENDING = &H6
  SERVICE_PAUSED = &H7
End Enum 

Private Declare Auto Function SetServiceStatus Lib "ADVAPI32.DLL" ( _
    ByVal hServiceStatus As IntPtr, _
    ByRef lpServiceStatus As SERVICE_STATUS _
) As Boolean
Private
_serviceStatus As SERVICE_STATUS

So the following is the code I used in the OnStart() method.

Protected Overrides Sub OnStart(ByVal args() As String)
  Dim handle As IntPtr = Me.ServiceHandle
  _serviceStatus.currentState = Fix(State.SERVICE_START_PENDING)
  SetServiceStatus(handle, _serviceStatus)
  Dim logMessage As String = String.Empty
  If Not ReadSettings(logMessage) Then
    WriteLogMessage(logMessage, EventLogEntryType.Error)
    _serviceStatus.currentState = Fix(State.SERVICE_STOPPED)
    SetServiceStatus(handle, _serviceStatus)
  Else
    If Not String.IsNullOrEmpty(logMessage) Then
      WriteLogMessage(logMessage, EventLogEntryType.Information)
    End If
    'Start the file watching...
    With FileSystemWatcher1
      .BeginInit()
      .Filter = _fileMask
      .IncludeSubdirectories = _includeSubFolders
      .Path = _folderName
      .EnableRaisingEvents = True
      .EndInit()
      _serviceStatus.currentState = Fix(State.SERVICE_RUNNING)
      SetServiceStatus(handle, _serviceStatus)
    End With
  End If
End Sub

So if everything works out the way it should I start the FileSystemWatcher by setting its EnableRaisingEvents property to True. In the OnStop() method I simply set this property to False to disable it.

When the FileSystemWatcher finds that the file that is being watched is created it raises the Created() event, in which I start a new thread that will simply sleep for the specified number of seconds and then check if the file still exists. If it does it sends the e-mail.

Private Sub FileSystemWatcher1_Created( _
    ByVal sender As Object, _
    ByVal e As System.IO.FileSystemEventArgs) Handles FileSystemWatcher1.Created
  If e.ChangeType = IO.WatcherChangeTypes.Created Then
    Dim thread As New Threading.Thread(AddressOf WatchFile)
    thread.Start(e.FullPath)
  End If
End Sub

Private Sub WatchFile(ByVal fullPath As Object)
  Dim fileName As String = CStr(fullPath)
  Threading.Thread.Sleep(_delayTime * 1000)
  If IO.File.Exists(fileName) Then
    SendMail()
  End If
End Sub

Private Sub SendMail()
  Dim mail As New System.Net.Mail.MailMessage
  For Each email In _eMailTo
    mail.To.Add(New Net.Mail.MailAddress(email))
  Next
  mail.From = New Net.Mail.MailAddress(_emailFrom)
  mail.Subject = _subject
  mail.Body = _body
  Dim smtpClient As New Net.Mail.SmtpClient(_smtpHost)
  With smtpClient
    .Port = _smtpPort
    If _requireAuthentication Then
      .Credentials = New Net.NetworkCredential(_authenticateName, _
_authenticatePassword) End If Try .Send(mail) Catch ex As Exception WriteLogMessage("Unable to send mail: " & ex.Message, _
EventLogEntryType.Error) End Try End With End Sub

Adding an installer to the project

Since this is a Windows Service it has to be installed as such so that it’s listed in the Service control panel applet. So you need to add an installer to the project. Note that this installer is not the same thing as a setup program, it will just add the necessary code that allows this application to be installed as a service using the InstallUtil.exe command line tool that comes with the .Net framework. More about that tool in a second.

To add an installer select your ServiceBase designer and right click on its surface and select Add Installer in the context menu. This will add a new Installer designer to your project that contains two component, a ServiceInstaller and a ServiceProcessInstaller.

Select the ServiceInstaller and change its DisplayName property. This will be the name that is listed in the control panel applet. You can also change the StartType property to Automatic if you want your service to start directly after it has been installed. In my case I left that property as Manual.

Now select the ServiceProcessInstaller and set the Account property to LocalSystem.

That’s it. You can now build the project. To do the installation open up a Visual Studio Command Prompt and type:

InstallUtil c:\thePath\theNameOfYourAssembly.exe

And presto! Your service should now be listed among the others in the Services control panel applet. Try to start and stop it from there. If you want to uninstall the service, which you must do if you need to make some changes to the source code, then type the following at the command prompt.

InstallUtil /u c:\thePath\theNameOfYourAssembly.exe

Conclusion

Even though this was a Windows Service with some very specific requirements I hope that this article have answered some questions on how you can create your own services.

Have fun!

Event horizon – Understanding custom events

Introduction

In this article I’m going to try to explain what custom events are and why you should use them in your code. As you will see the term custom event in this context is not just an event you have created for your own class, but also a custom way of storing the delegates for this event.

Most of this article is intended for the VB developer, but with the exception of VB specific parts, especially found in the Background Info section, the information here also applies to C# (but with a slightly different syntax of course).

Background info

If you have used VB or any other .Net language for an extended time, you have probably created one or two user controls, or regular classes that raises events. Events in the .Net framework are implemented as properties that accepts a delegate. A delegate is similar to a function pointer in C or C++ although a delegate is strongly typed. I wont dwelve into the difference between a function pointer and a delegate in this article, since that would be an article of its own. Instead I will just simplify and say that a delegate is an address to a method that will be called by the handler (in this case its the object that exposes the event).

If you want to handle an event raised by an object you can use the AddHandler statement. But VB also has a simplified solution using the Handles keyword. If you drop a Button on a Form you could then handle its click event like this:

Private Sub Button1_Click(ByVal sender As System.Object, _
                          ByVal e As System.EventArgs) Handles Button1.Click
  'code for the click event goes here
End Sub

The above code will be called when the Click event occur for the object named Button1. This is made possible by another VB specific keyword that’s been around since VB5, the WithEvents keyword.

When you drop the button on the Form the designer will create the code that declares and initializes the component for you. The declaration of the button the designer creates looks like this:

Friend WithEvents Button1 As System.Windows.Forms.Button

You can use this syntax yourself in your code to handle events raised by objects without the need to call the AddHandler statement. However for clarity I will show the AddHandler approach as well. If the designer wouldn’t use the WithEvents keyword, you wouldn’t be able to use the Handles keyword either to handle the event.

Friend Button1 As System.Windows.Forms.Button

In this case you would need to use the AddHandler in our code.

Private Sub Form1_Load(ByVal sender As Object, _
                       ByVal e As System.EventArgs) Handles Me.Load
  AddHandler Button1.Click, AddressOf Button1_Click
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, _
                          ByVal e As System.EventArgs) 'No Handles keyword
  'code for the click event goes here
End Sub

Creating your own events

It’s very easy to let your own classes/controls expose events. In most cases you would probably declare your events like this within your class:

Public Event MySpecialEvent(ByVal sender As Object, ByVal e As EventArgs)

A class that have the above will expose a MySpecialEvent event. But this is not enough. It’s when you raise the event the code in the event handlers is being executed. So whenever it is time to raise MySpecialEvent you would use code like this:

RaiseEvent MySpecialEvent(Me, New EventArgs)

If you’re coming from a VB6 background, this will seem very familiar to you.

You might call the above a custom event, since that’s what it is. My class has a custom event called MySpecialEvent which I have implemented using the technique I just demonstrated. But as I mentioned in the introduction section, custom event (in the lack of a better name) in this context is much more than this. For Custom events you need to keep track of all the event handlers that is used. More about that in the next section.

Custom events = keeping track of event handlers

There is a problem with how we created our own events in the previous section: It can become a huge waste of memory resources.

Let me again take a regular Button in a Windows Forms application as an example. The Button component exposes no less than 68 different events. If they all would be declared with the Public Event EventName syntax, it would require that 68 fields needs to be created. Lets say a Form contains 10 buttons, that is 680 fields, and in the most likely scenario 670 of these are never used since we’re probably only interested in the Click event. So what we end up with are objects that takes longer to instantiate and more usage of heap memory that can’t be reclaimed, unless you remove the control from the Form and dispose it (and how often do you do that with controls you’ve added to a Form?).

So if you create your own user control or regular class that exposes many events you need a custom event storage. There is a special collection class called EventHandlerList in the Framework, available in the System.ComponentModel namespace, which we can use to store the event handlers.

Let’s say I create a class that contains a few typical mouse events and take advantage of the EventHandlerList to store all event handlers, I would write code similar to the following.

Public Class CommonMouseEvents

  Private events As New System.ComponentModel.EventHandlerList
  Public Custom Event Click As EventHandler
    AddHandler(ByVal value As EventHandler)
      events.AddHandler("OnClick", value)
    End AddHandler

    RemoveHandler(ByVal value As EventHandler)
      events.RemoveHandler("OnClick", value)
    End RemoveHandler

    RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
      Dim value As EventHandler = CType(events("OnClick"), EventHandler)
      value.Invoke(sender, e)
    End RaiseEvent
  End Event

  Public Custom Event DoubleClick As EventHandler
    AddHandler(ByVal value As EventHandler)
      events.AddHandler("OnDblClick", value)
    End AddHandler

    RemoveHandler(ByVal value As EventHandler)
      events.RemoveHandler("OnDblClick", value)
    End RemoveHandler

    RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
      Dim value As EventHandler = CType(events("OnDblClick"), EventHandler)
      If value IsNot Nothing Then
        value.Invoke(sender, e)
      End If
    End RaiseEvent
  End Event
  'Move event declarations go here...
End Class

Here we first create an instance of the EventHandlerList class, and then I declare my events.

Notice the Custom keyword and that the event must be declared as an EventHandler or one of its child classes. Inside the event declaration you must write code for the AddHandler(), RemoveHandler(), and RaiseEvent() procedures (the stub for these are added automatically by the designer in Visual Studio).

Now, the above is just the declaration of the events and the custom code to store, remove, and invoke the event handlers. You must still raise the events in the normal fashion, using the RaiseEvent statement.

What exactly are the EventHandlerList?

In the previous section I called the EventHandlerList a collection, but that is not really true. It doesn’t implement the IEnumerable interface, it is instead implemented as a linked list. That means that even though we save a great deal of memory space, we might have a trade-off in access speed since we need to search the list from front to end for an event handler. In the case a event handler doesn’t exist we need to traverse the whole list.

So why wasn’t this list implemented as a hash table instead? The answer is pretty simple, the list will probably not be very large. Normally you will probably not use more than say 10 events (and in most cases probably less than that) on a given object, and with that small amount of data a linked list is actually much faster than a hash table.

Have fun!

kick it on DotNetKicks.compimp itShout it

Run you later – Understanding deferred execution in LINQ

Introduction

In this article I’m going to try to explain one of the most misunderstood features of LINQ – deferred execution – and the impact it might have on your code if you don’t fully understand what it means.

What does deferred execution mean?

According to the dictionary the word deferred means delayed or postponed. So deferred execution in LINQ means that the actual execution of a query is postponed to a later time. Let’s say that you’re using LINQ to SQL and want to use the following LINQ query:

Dim cheapProducts = From p In db.Products _
                    Where p.ListPrice < 100 _
                    Select p

It’s easy to assume that the above will execute a query against the underlying database, but it wont. It will just create an IQueryable that has a reference to something that knows how this query can be executed (when it comes to LINQ to SQL this reference will point to an expression tree, but you don’t have to know about that since that’s just an implementation that the LINQ to SQL provider uses), but it will not run the actual query. LINQ has postponed, or deferred, the execution to a later time.

-To a later time, you say. So when is that exactly?

In LINQ the execution of a query is performed when you request the data, for example in a loop.

For Each prod In cheapProducts
  Console.WriteLine("The list price for {0} is {1}", prod.ProductName, prod.ListPrice)
Next

But you might request the data earlier. Take the following query as an example.

Dim productList = (From p In db.Products _
                   Where p.ListPrice < 100 _
                   Select p).ToList()

In this case we request that the result of the query is turned into a List(Of Product). To be able to do that the query has to be executed. But that doesn’t really mean that we didn’t have a deferred execution, it just wasn’t delayed for very long since we immediately request that the data should be turned into a list. This would also be true if we instead of requesting a list would call the Count() extension method or anything else that wouldn’t return an IEnumerable(Of T) or an IQueryable(Of T).

What kind of implications might this have on my code?

For the purpose of this article I’m going to use a Person class that only have a FirstName and LastName property and a little helper method that fills a List(Of T) with a number of persons, which will be used as the data source of our queries. In other words I’m going to use LINQ to Objects, but the same rules apply even if you use any other LINQ provider such as LINQ to SQL or LINQ to XML.

Public Class Person
  Private _firstName As String
  Public Property FirstName() As String
    Get
      Return _firstName
    End Get
    Set(ByVal value As String)
      _firstName = value
    End Set
  End Property

  Private _lastName As String
  Public Property LastName() As String
    Get
      Return _lastName
    End Get
    Set(ByVal value As String)
      _lastName = value
    End Set
  End Property

  Public Sub New(ByVal firstName As String, ByVal lastName As String)
    _firstName = firstName
    _lastName = lastName
  End Sub

  Public Shared Function GetPersonList() As List(Of Person)
    Dim list As New List(Of Person)
    With list
      .Add(New Person("Bart", "Simpson"))
      .Add(New Person("Lisa", "Simpson"))
      .Add(New Person("Maggie", "Simpson"))
      .Add(New Person("Homer", "Simpson"))
      .Add(New Person("Marge", "Simpson"))
      .Add(New Person("Ned", "Flanders"))
      .Add(New Person("Maude", "Flanders"))
      .Add(New Person("Rod", "Flanders"))
      .Add(New Person("Todd", "Flanders"))
    End With
    Return list
  End Function
End Class

Now let’s say we have the following code.

Public Sub Main()
  Dim personList As List(Of Person) = Person.GetPersonList()

  'Get a list of the Simpsons family
  Dim lastName As String = "Simpson"
  Dim persons = From p In personList _
                Where p.LastName = lastName _
                Select p

  lastName = "Flanders"
  For Each pers In persons
    Console.WriteLine("{0} {1}", pers.FirstName, pers.LastName)
  Next
End Sub

Which are the names that will be written to the console? If you guessed the names of the Simpsons, you haven’t paid attention. The query asks for all persons with the last name “Simpson”, but still the name of the Flanders are written out. Remember that the query is not executed when we define it but rather when we ask for the data. Since we change the lastName variable before the query is executed we have in fact changed the query.

The fact that the execution is delayed until we ask for the data also means that we can reuse the same query. Let’s make some slight changes to the last example.

Public Sub Main()
  Dim personList As List(Of Person) = Person.GetPersonList()

  'Get a list of the Simpson's family
  Dim lastName As String = "Simpson"
  Dim persons = From p As Person In personList _
                Where p.LastName = lastName _
                Select p

  For Each pers In persons
    Console.WriteLine("{0} {1}", pers.FirstName, pers.LastName)
  Next
  Console.WriteLine("---------------")
  'Change the last name
  lastName = "Flanders"
  'Reuse the query
  For Each pers In persons
    Console.WriteLine("{0} {1}", pers.FirstName, pers.LastName)
  Next
  Console.ReadLine()
End Sub

In this example we first write out the names of the Simpson family. Then we change the lastName variable and loop through it again. Since the query has been changed it will be executed a second time and we’ll get the names of the Flanders family. We reused the same query to get two different results.

Conclusion

LINQ is wonderful thing. It allows you to do complex things with very few lines of code and that can surely bring a big smile to your face. However, that smile can easily be turned into a stupid looking grin if you don’t understand deferred execution. If you don’t understand exactly when the query will be executed you might present completely erroneous data to your end users.

Have fun!

The Untouchables (part III) – Adding iterators to our immutable stack

Introduction

In my last post I showed you a VB translation of Eric Lippert’s immutable stack class. There was however one thing that was lost in translation. In Eric’s original code he made the class enumerable (added support for a For Each loop). Because C# has support for iterators with its yield keyword, that was very easy to do… in C#. VB currently doesn’t have this feature so to add the same support we need to implement both the IEnumerable(Of T) and the IEnumerator(Of T), which in turn requires the implementation of the non-generic IEnumarable and IEnumerator and also the IDisposable interfaces.

The Interfaces

Fig1

As you can see from the above image, that is 7 members that we have to implement. That might sound like a lot, but fortunately it’s mainly boiler-plate code. Firstly, the Reset() method of the IEnumerator interface is rarely used and in our case we will simply throw an NotImplementedException in that method. Secondly, we will end up with two GetEnumerator() methods and two Current() properties. But in our case we will simply make the non-generic versions of these members private and call the generic versions from them. Thirdly, in our case we will not change the code that the designer adds to the Dispose() method of the IDisposable interface, except for one little detail. The designer will mark the Dispose() method as Overridable, but since our Stack() class is sealed (NotInheritable) we only need to remove that keyword.

That leaves us with only 3 members to which we need to add our logic, the IEnumarable(Of T).GetEnumerator() method, the IEnumerator(Of T).Current() property, and the IEnumerator.MoveNext() method.

The implementation

To add support for all of this we first have to make a change to our IStack(Of T) interface.

Public Interface IStack(Of T)
  Inherits IEnumerable(Of T), IEnumerator(Of T)

Function Push(ByVal value As T) As IStack(Of T) Function Pop() As IStack(Of T) Function Peek() As T ReadOnly Property IsEmpty() As Boolean End Interface

If you add this to your existing code, you will get the following in our class implementation:

image

To fix that simply put the text caret at the end of the Implements line and press the enter key. That will allow the designer to add the empty method and property procedures that we need to implement.

Since there will be two Current() properties and two GetEnumerator() methods, I simply rename the non-generic versions of these and make them private. From them we simply call the generic versions. In the Reset() method we simply throw an NotImplementedException.

Private Function IEnumerator_GetEnumerator() As System.Collections.IEnumerator _
    Implements System.Collections.IEnumerable.GetEnumerator
  Return GetEnumerator()
End Function

Private ReadOnly Property IEnumerator_Current() As Object _
    Implements System.Collections.IEnumerator.Current
  Get
    Return Current
  End Get
End Property
Public Sub Reset() Implements System.Collections.IEnumerator.Reset
  Throw New NotImplementedException()
End Sub

The important members to implement is the GetEnumertor() and the MoveNext() methods plus the Current() read-only property. In a regular class that implements these interfaces we would simply return Me in the GetEnumertor() method. However since our stack is immutable we can’t do that since we don’t change the current instance when we Pop a value from the stack. So instead we add a private instance of the object that we will change when needed. We also need a private field to hold the current value.

Private _enumerator As IStack(Of T) = Me
Private _currentValue As T

As you can see we initialize the _enumertor to be a reference to the current object,  Me. This is what we return from the GetEnumerator() method.

Public Function GetEnumerator() As  _
    System.Collections.Generic.IEnumerator(Of T) _
    Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator
  Return _enumerator
End Function

In the MoveNext() method we are supposed to return a boolean value if we can move to the next object. In our case we simply need to check our IsEmpty() property, if that is false then we can return another item. We also set the _currentValue field to the current value and Pop it from the stack.

Public Function MoveNext() As Boolean _
    Implements System.Collections.IEnumerator.MoveNext
  If Not _enumerator.IsEmpty Then
    _currentValue = _enumerator.Peek()
    _enumerator = _enumerator.Pop()
    Return True
  Else
    Return False
  End If
End Function

In the Current() property we simply return the _currentValue field that was set in the previous method.

Public ReadOnly Property Current() As T _
    Implements System.Collections.Generic.IEnumerator(Of T).Current
  Get
    Return _currentValue
  End Get
End Property

That’s pretty much it. We can now iterate throw our Stack using code similar to this:

Public Sub Main()
  Dim myStack As IStack(Of String) = Stack(Of String).Empty
  'init the stack
  For i As Integer = 0 To 25
    myStack = myStack.Push(ChrW(Asc("A") + i).ToString)
  Next
  'Use a For Each loop on the stack
  'Note, since a stack is last in-first out,
  'the alphabet will be written in reversed order here
  For Each s As String In myStack
    Console.Write(s)
  Next
End Sub

Conclusion

As you’ve seen, since VB currently doesn’t support iterators in the same manner as C# does, we need to add a lot more code to our class to support it. Most of it are boiler-plate code though so it’s not as hard as it might look at a first glance. If you’re interested in learning more about how to use iterators in VB I highly recommend that you read this Visual Studio Magazine article written by Bill McCarthy.

You can download the code for this article here.

Have fun!