The majority of the source code presented in the previous chapters has mainly used the block construct and its accompanying matching braces to mark out the context of a class or to delineate the context of methods, the Main() method in particular.
With the introduction of if-else statements and their ability to contain blocks of code (compound statements), you will begin to create programs containing several layers of nested blocks inside and next to each other. It is, therefore, important to introduce a new concept closely related to the block construct called scope. The scope determines which segments (and hence variables) of the source code are visible (and hence accessible) to other parts of the source code. Scope is the technical term used for the informal word context.
Scope is the segment of the source code where a particular variable identifier can be used. Variables can only be used inside their scope. The block of source code in which a variable is declared defines the scope of the variable.
Two of the major scopes in C# are those marked out by the class block and the method block, as illustrated in Figure 8.14. Even though the distinction between these two blocks might be somewhat artificial, the class scope contains several distinctive characteristics not found within the method scope. For example, it is only possible to insert if-else statements inside the method scope. Consequently, the class scope discussion is deferred until the detailed discussion of the class concept in Chapter 12, "Class Anatomy Part I: static Class Members and Method Adventures." The rest of the discussion here is focused on the method scope and blocks (scopes) nested inside it.
You don't need constructs like the if-else statements to create a block inside another block. A new block, and thereby a new scope, can simply be created by inserting a couple of matching braces, as shown in Figure 8.15. When a block, here named B, is inserted inside another block A, the scope formed by block B is said to be the inner scope, and the scope formed by block A is the outer scope. Inner and outer are relative terms, thus making the scope of block A inner relative to the outer Main() block scope. Notice that the names A and B are used merely for illustrative purposes; blocks created simply by adding a couple of braces do not carry any name tags and cannot be referenced as such.
A local variable is a variable declared within a method.
Variables declared inside a method block are not accessible from outside this block and are referred to as local variables.
As a rule of thumb, variables declared inside a block are only accessible from code written within this block (including that of other inner blocks inserted here) and after the declaration of the variable. A variable can be declared at any position within a block.
Figure 8.16 illustrates the effect of these rules. It contains two blocks of code. One block belongs to the Main() method, and the other to an if statement, which is positioned inside the Main() block. Because distance is declared at the beginning of the outer scope, it is accessible throughout the code of Main(), including the code inside the inner if statement block. On the other hand, because mass is not declared until towards the end of Main(), it is only accessible in the relatively small segment of code between this declaration and the end of the Main() scope. The energy variable is declared inside the if statement block and is only accessible within this block.
It is an error to declare a variable in an inner scope with a name identical to that of a variable in an outer scope (see Figure 8.17). The reason for this is that this would give a different meaning to the variable name of the outer scope.
On the other hand, it is possible, albeit perhaps confusing, to declare two variables with the same name in two blocks both residing inside the same block but existing next to each other, rather than nested inside each other. Figure 8.18 illustrates.
Recall our discussion about variable names (identifiers) as a convenient means to reference specific locations in memory. When discussing the scope concept, it is important to separate the ability to use a certain name to reference the underlying data residing inside the memory (the scope) from the time the underlying memory itself exists. The latter is referred to as the lifetime of a variable. The difference between scope and lifetime is illustrated in Figure 8.19.
The lifetime of a variable is the time between the creation and the destruction of a variable. From the time a variable is created, its value is retained somewhere in the computer memory. This preservation lasts until its destruction.
The reference from a name of a variable to the data in memory, which it represents is often referred to as a binding.
As a general rule, variables in C# are created when the program flow enters their scope and destroyed when it leaves their scope. As a result, the lifetime of a variable is confined to its scope.
Even though the rule put forth in the previous note seems obvious, it does not hold for all computer languages. Some languages allow the program flow to enter and leave the scope of a variable numerous times while preserving the value of the variable. Thus, every time the scope is re-entered, the variable has the same value it had just before leaving the scope at the previous visit.