Introduction to the Singleton Pattern in VB.NET
September 13th, 2007
Most VB programmers, even those who’ve haven’t used VB.NET much, know that to create an object they invoke it by calling the class’s constructor using the New keyword. Those who’ve worked with VB.NET may know that there can be multiple constructors for a class and that the .NET Framework automatically builds a no-argument constructor behind the scenes for you at compile time if you don’t supply one. All of these constructors have a Public access modifier so that they can be created from outside the class. Sometimes, there will be cases where you only want one instance of a class in your application. This is where the Singleton Pattern comes into play.
Coding the Singleton Class
There are three steps to creating a simple Singleton class.
First, we will also want to have a module level Private Shared variable that holds the single instance we’re creating:
Public Class MySingleton
Private Shared _thisInstance As MySingleton
End Class
Next, we want to create a single constructor method with a Protected access modifier, like so:
Public Class MySingleton
Private Shared _thisInstance As MySingleton
Protected Sub New()
'initialization code goes here
End Sub
End Class
This prevents .NET from creating a default Public constructor and also prevents any caller from creating their own instance of the object. However, by using Protected, the class can still be subclassed if you need to do this.
Lastly, we want to create a Shared accessor method for the class. It would look like this:
Public Class MySingleton
Private Shared _thisInstance As MySingleton
Protected Sub New()
'initialization code goes here
End Sub
Public Shared Function GetSingleton() As MySingleton
'
' initialize object if it hasn't already been done
'
If _thisInstance Is Nothing Then
_thisInstance = New MySingleton
End If
'
' return the initialized instance
'
Return _thisInstance
End Function
End Class
Since this ‘get’ routine is Shared it can be called without having an instance of the object, as seen here.
Dim TestStuff As MySingleton = MySingleton.GetSingleton Dim MoreStuff As MySingleton = MySingleton.GetSingleton
In this example both TestStuff and MoreStuff are the same object instance, just with different names. That concept seems a bit confusing at first but don’t let that throw you. Just keep in mind that no matter how many variables you use to hold an instance of your Singleton class, it is actually always the same instance.
When Should You Use the Singleton Pattern?
A common place to use this pattern is with forms. You can easily make a form a Singleton class by following the steps above. The only thing you might want to override the OnClosing event to keep the form open but hidden, like so:
Protected Overrides Sub OnClosing(ByVal e As System.ComponentModel.CancelEventArgs)
e.Cancel = True
Me.Hide()
End Sub
This technique with forms allows you to insure that only a single instance of a particular form is open at once. This is handy for search forms, certain kinds of pop-ups, and other forms commonly used throughout the application.
Using a Singleton is effective in situations where you need to prevent multiple copies of an object. For example, if you had a device driver for a device that only allowed a single connection at a time, a Singleton would be a good solution.
Another use would be in situations where you wanted to cloak the actual instantiation process or otherwise limit usage of a component. I’ve seen this used for proprietary classes and controls in add-on tools where the programmer wanted to hide initialization details from purchasers or limit trial period users.
There are also some drawbacks to using Singletons as well.
First, they can be a pain for other developers to work with. They’re expecting to use a New call but instead have to use a custom initializer. This can be annoying if there isn’t a good and well documented reason behind it. So, always consider your fellow developers when you implement the Singleton pattern.
Another thing to consider is that you may lose some flexibility in how and when the internal object is created based on how the program runs. This is particularly important in classes and components you provide beyond your own applications. Once again, consider other developers.
Using this pattern can lead to some of the problems associated with global variables. Like Globals, it can make a program harder to debug since state changes can come from anywhere. Because of this, I recommend avoiding putting stateful variables in these classes. Also, simply replacing your global variables with a Singleton class isn’t considered a good design practice. It only gives you the illusion of being object oriented. Avoid using this pattern this way.
I hope this introductory overview has been helpful to you. If you have any thoughts or questions on this topic, please feel free to leave me a comment.
Entry Filed under: VB.NET Tutorials
Rate This Article:










7 Comments Add your own
1. Joe | September 14th, 2007 at 10:19 am
Would something like this do it?
Public Class Singleton(Of T As {Class, New}) Public Shared ReadOnly Property Instance() As T Get Return SingletonCreator._instance End Get End Property Class SingletonCreator Shared Sub New() End Sub Friend Shared ReadOnly _instance As New T() End Class End Class2. jfrankcarr | September 14th, 2007 at 11:40 am
Thanks Joe. I reformatted your code for readability.
Yes. That would work for creating a generic Singleton object. The only limitation is that you can only use objects that have a Public New that takes no parameters. String would be an example of an object that would not work although you could wrapper it in another class easily enough if you wanted.
The interesting thing about this code example is that you can use this Singleton provider to create a Singleton version of a class without having to have the code in the class itself.
Thanks again for a great example.
3. jamesewelch | September 14th, 2007 at 1:19 pm
Also, the VB.NET Module is implemented as a Singleton, it just doesn’t use lazy instantiation such as this example does. So that makes it just a class with all properties/methods declared as static/shared.
Public Module MySingleton
End Module
4. jamesewelch | September 14th, 2007 at 1:23 pm
Oh.. Also, you might want to talk about using a lock to make sure there isn’t two different instantiations of the singleton that happen at the same time.
example in c#
http://www.yoda.arachsys.com/csharp/singleton.html
5. jfrankcarr | September 14th, 2007 at 1:56 pm
Thanks James,
Threading certainly does throw a whole new wrinkle on things. The article you linked to is very informative and helpful.
To implement the second version, simple thread-safety, mentioned in the linked article, my code example should look like this, if I followed it correctly:
Public Class MySingleton Private Shared _thisInstance As MySingleton Private Shared PadLock As New Object Protected Sub New() 'initialization code goes here End Sub Public Shared Function GetSingleton() As MySingleton ' ' Prevents multiple threads from creating ' separate instances ' SyncLock PadLock ' ' initialize object if it hasn't already been done ' If _thisInstance Is Nothing Then _thisInstance = New MySingleton End If ' ' return the initialized instance ' Return _thisInstance End SyncLock End Function End ClassJames’ code would be the fifth version, fully lazy instantiation, is that correct?
Thanks again for everyone’s input.
6. Antonio Cavallaro | June 19th, 2008 at 12:51 am
This is my code for full thread-safety:
”’
”’ Singleton generic thread safe
”’
”’
”’ Codebase by A.Cavallaro
Public Class Singleton(Of T As {Class, New})
Private Shared ReadOnly l_ThreadSafeIstance As New T
”’
”’ Ritorna l’istanza thread-safe del singleton
”’
”’
”’
Public Shared Function GetInstance() As T
Return l_ThreadSafeIstance
End Function
”’
”’ Nessun costruttore per singleton
”’
”’
Private Sub New()
End Sub
End Class
7. Antonio Cavallaro | June 19th, 2008 at 12:52 am
Pardon, my personal thread-safe singleton generic object:
'''
''' Singleton generic thread safe
'''
'''
''' Codebase by A.Cavallaro
Public Class Singleton(Of T As {Class, New})
Private Shared ReadOnly l_ThreadSafeIstance As New T
'''
''' Ritorna l'istanza thread-safe del singleton
'''
'''
'''
Public Shared Function GetInstance() As T
Return l_ThreadSafeIstance
End Function
'''
''' Nessun costruttore per singleton
'''
'''
Private Sub New()
End Sub
End Class
Leave a Comment
Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>
Trackback this post | Subscribe to the comments via RSS Feed