As you saw earlier in this chapter, the scope of a data item determines what parts of a program can have access to that item. You can think of scope in terms of its restrictiveness. Block scope limits the accessibility of a data item to the block in which it is defined. Local scope limits access to the statement body of the procedure in which it is defined. Module scope limits access to the module in which the definition occurs. Namespace scope expands module scope to include all classes within the assembly, provided that you've used the proper access specifiers (for example, Public and Shared ).
The concept of the lifetime of a data item or object is slightly different from the concept of scope. Suppose you have the following code fragment in a program:
Private Sub btnCalc_Click(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles btnCalc.Click Dim Counter As integer Counter = Counter + 1 End Sub
In this example, the variable Counter is defined with local scope. Each time the btnCalc object's Click() event is executed, Counter is defined and incremented. Because Counter has local scope, its lifetime is limited to the time it takes to execute the btnCalc object's Click() event. Counter 's life ends when the End Sub is reached.
However, suppose you want to keep track of how many times the user clicks the btnCalc button. Clearly, because the lifetime of Counter extends only to the end of the Click() event, the largest count you will ever have is 1 . Because Counter is "reborn" each time the user clicks the Calculate button, it is initialized to each time you enter the procedure.
What you really want to do is extend Counter 's lifetime beyond that associated with a normal variable with local scope. You would like Counter not to be reborn each time you enter the btnCalc object's Click() event, but extend its lifetime to that of the program. That is, as long as the program is running, the same definition of Counter exists in the program.
The Static Storage Class
What you need is a way to prevent a variable from dying when it goes out of scope. To extend Counter 's lifetime, you can change its definition as follows :
Static Counter As Integer
The Static keyword changes the way the Counter variable is defined in the program. The Static keyword causes Visual Basic .NET to make a special notation in the symbol table that says: "Even when this variable goes out of scope, do not destroy it. Keep its lvalue in the symbol table, and never re-create it, even if we enter this procedure another time." In other words, after a static variable is defined, it doesn't go away until the program ends. Therefore, its lifetime is the same as the program's lifetime. As long as the program is running, Counter exists.
This means that Counter can now hold its current value, even after you leave the scope in which it is defined. Big deal, you say. Why not just give Counter namespace scope by moving its definition outside btnCalc and give it shared public access? Well, that would work, but you would lose one important advantage: With the Static keyword, the scope of Counter is still local to btnCalc . Because Counter 's scope is still local, nothing else in the program can inadvertently change its value! Data hiding is almost always good.
Keep in mind that the Static keyword extends the lifetime of a data item but does not change its scope. Using the Static keyword is perfect for data items that must track a running total of something but that you don't want to expose to other sections of the program.