Shared Methods, Variables, and Events
So far, all of the methods we've built or used
have been instance
methods methods that require us to have an actual instance of
the class before they can be called. These methods have used instance variables
or member variables to do their work meaning that they have been working with
a set of data that is unique to each individual object.
VB.NET allows us to create variables and methods that belong
to the class rather than to any
specific object. Another way to say
this is that these variables and methods belong to all objects of a
given class and are shared across all the
instances of the class.
We can use the Shared
keyword to indicate which variables and methods
belong to the class rather than to specific objects. For instance, we may be
interested in knowing the total number of Person
objects created as our
application is running kind of a statistical counter.
Shared Variables
Since regular variables are unique to each individual Person
object, they don't allow us to easily track the total number of Person
objects ever created. However, if we had a variable that had a common value across
all instances of the Person
class, we could use that as a counter. Add the following variable declaration
to our Person
class:
Public Class Person
Implements IDisposable
Private Shared sintCounter As Integer
By using the Shared
keyword, we are indicating that this variable's value should be shared across
all Person
objects within our application. This means that if one Person
object makes the value be 42, all other Person
objects will see the value as
42 it is a shared piece of data.
We are using the
letter "s"
as a prefix to this variable rather than "m".
The letter "m" is commonly used for member variables (or module
variables), but this variable is not a member variable it is a shared
variable.
Using a different prefix can help distinguish between member and shared
variables within our code.
We can now use this variable within our code. For instance,
we can add code to the constructor method, New,
to increment the variable so it
acts as a counter adding 1 each time a new Person
object is created. Change the New
methods as shown:
Public Sub New()
Phone("home") = "555-1234"
Phone("work") = "555-5678"
sintCounter += 1
End
Sub
Public Sub New(ByVal Name As String, ByVal BirthDate As Date)
mstrName = Name
mdtBirthDate = BirthDate
Phone("home") = "555-1234"
Phone("work") = "555-5678"
sintCounter += 1
End
Sub
The sintCounter
variable will now
maintain a value indicating the total number of Person
objects created during the life of our application. We may want to add a
property routine to allow access to this value by writing the following code:
Public ReadOnly Property PersonCount() As Integer
Get
Return sintCounter
Notice that we're creating a regular property that returns
the value of a shared variable. This is perfectly acceptable. As we'll see
shortly, we could also choose to create a shared property to return the value.
Now we could write code to use our class as follows:
Dim myPerson As Person
myPerson = New Person()
myPerson = New Person()
myPerson = New Person()
MsgBox(myPerson.PersonCount)
The resulting display would show 3
since we've created three instances of the Person
class.
Shared Methods
We cannot only share variables across all instances
of our class, but we can also share methods. Where a regular method or property
belongs to each specific object, a shared method or property is common across
all instances of the class.
There are a couple of ramifications to this approach.
First off, since shared methods don't belong to any specific
object, they can't access any instance variables from any objects. The only
variables available for use within a shared method are shared variables,
parameters passed into the method, or variables declared locally within the
method itself. If we attempt to access an instance variable within a shared
method, we'll get a compiler error.
Also, since shared methods
are actually part of the class rather
than any object, we can write code to
call them directly from the class without having to create an instance of the
class first.
For instance, a regular instance method is invoked from an
object:
Dim myPerson As New Person()
myPerson.Walk(42)
but a shared method can be invoked directly from the class
itself:
This saves the effort of creating an object just to invoke a
method, and can be very appropriate for methods that act on shared variables,
or methods that act only on values passed in via parameters. We can also invoke
a shared method from an object just like a regular method. Shared methods are
flexible in that they can be called with or without creating an instance of the
class first.
To create a shared method we again use the Shared keyword. For instance, the PersonCount
property we created earlier could easily be changed to be a shared method
instead:
Public Shared ReadOnly Property PersonCount() As Integer
Get
Return sintCounter
End Get
End Property
Since this property returns the value of a shared variable,
it is perfectly acceptable for it to be implemented as a shared method. With
this change, we can now find out how many Person
objects have ever been created
without having to actually create a Person
object first:
MsgBox(Person.PersonCount)
As another example, in our Person
class we could create a method that compares the ages of two people. Add a
shared method with the following code:
Public Shared Function CompareAge(ByVal Person1 As Person, _
ByVal Person2 As Person) As Boolean
Return Person1.Age > Person2.Age
End
Function
This method simply accepts two parameters each a Person
and returns True
if the first is older than the second. The use of the Shared
keyword indicates that this method doesn't require a specific instance of the Person
class for us to use it.
Within this code, we are invoking the Age
property on two separate objects the objects passed as parameters to the
method. It is important to recognize that we're not directly using any
instance variables within the method, but rather
are accepting two objects as parameters and are invoking methods on those
objects.
To use this method, we can call it directly from the class:
If Person.CompareAge(myPerson1, myPerson2)
Then
Alternately, we can also invoke it from any Person
object:
Dim myPerson As New Person()
If myPerson.CompareAge(myPerson, myPerson2)
Then
Either way, we're invoking the same shared method and we'll
get the same behavior whether we call it from the class or a specific instance
of the class.
Shared Properties
As with other types of methods, we can also have shared
property
methods. Properties follow the same rules as regular methods they can
interact with shared variables, but not member variables, and they can invoke
other shared methods or properties, but can't invoke instance methods without
first creating an instance of the class.
We can add a shared property to our Person
class with the following code:
Public
Shared ReadOnly Property RetirementAge() As Integer
Get
Return 62
End Get
End
Property
This simply adds a property to our class that indicates the
global retirement age for all people. To use this value, we can simply access
it directly from the class:
MsgBox(Person.RetirementAge)
Alternately, we can also access it from any Person
object:
Dim myPerson As New Person()
MsgBox(myPerson.RetirementAge)
Either way, we're invoking the same shared property.
Shared Events
As with other interface elements, events can also be marked as Shared.
For instance, we could declare a shared event in the Person
class such as:
Public Shared Event NewPerson()
Shared events can be raised from both instance methods and
shared
methods. Regular events can not be raised by shared methods. Since shared
events can be raised by regular methods, we can raise this one from the
constructors in the Person class:
Public
Sub New()
Phone("home") = "555-1234"
Phone("work") = "555-5678"
sintCounter += 1
RaiseEvent NewPerson()
End
Sub
Public Sub New(ByVal Name As String, ByVal BirthDate As Date)
mstrName = Name
mdtBirthDate = BirthDate
Phone("home")
= "555-1234"
Phone("work") = "555-5678"
sintCounter += 1
RaiseEvent NewPerson()
End
Sub
The interesting thing about receiving shared events is that
we can get them from either an object, like a normal event, or from the class
itself. For instance, we can use
the AddHandler
method in our form's code to catch this event directly from the Person class.
First let's add a method to the form to handle the event:
Private Sub OnNewPerson()
MsgBox("new person " & Person.PersonCount)
End
Sub
Then, in the form's Load
event, add a statement to link
the event to this method:
Private Sub Form1_Load(ByVal
sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
AddHandler Person.NewPerson, AddressOf OnNewPerson
mobjPerson = New Person()
If Microsoft.VisualBasic.Command = "nodisplay" Then
AddHandler mobjPerson.Walked, AddressOf LogOnWalk
Else
AddHandler mobjPerson.Walked, AddressOf OnWalk
End If
End
Sub
Notice that we are using the class rather than any
specific object in the AddHandler
statement. We could use an object as well treating this like a normal event,
but this illustrates how a class itself can raise an event.
When we run the application now, any time a Person
object is created we'll see this event raised.