Variable scoping
Each variable is only available (and accessible) in the context within which it has been declared. To determine the context, refer to the closest opening and closing marks that surround the declaration. Most programming languages use curly braces ({}
) to mark the beginning and the end of a block of code. Check out this example:
There's no need to understand every bit of code here; just focus on the curly braces. 🙂 When we talk about the availability of a variable within a context, we're referring to scope. Here, you can see that the variable root
has been declared between the two curly braces circled in purple. The scope of that variable is everything between those two braces.
The scope of a variable can be local as well as global, depending on where a variable is declared. A global variable can be available to all the classes and methods within a program while a local variable might only be available within the method that it is declared in:
Here, we've expanded the code a little and extended our first block of code to include another one! If you trace the purple lines, you can see that the brackets from the first block encompass all the code from the second one. Next, you can see that a new variable, spy
, has been declared within the green local scope.
Since the root
variable has been declared in the global scope, that means it is accessible to everything within the purple brackets, including everything declared in the local scope. In the second block of code, you can see a line just below the spy variable declaration which uses root
. That's allowed!
However, whatever is in the local scope is not available to the global scope, or any other local blocks of code. Let's take a look at another example:
Here we've added another block of code, which has its own local scope and variable, anotherSpy
. Now, check out the last line in our spy variable block:
Console.WriteLine(anotherSpy); // Error
It looks like there's an error! That's because it's trying to use the anotherSpy
variable. But it can't because anotherSpy
is neither within the global scope nor in the same local scope. That means that this block of code can't access it. The anotherSpy
variable is only available in the block of code it's been declared in.
The same is true in the other direction. You can see that the last line of our last block of code also has an error:
Console.WriteLine(spy); // Error
Here, it's trying to use the variable spy
from another block of code. But it can't since spy
isn't in the same scope as the code block that's trying to use it.
Variable scope in classes
When you declare a class, the same general rules of scoping apply: each variable is only accessible within its declaration block. Let's experiment with a unicorn class:
Just like in the first example, there are global as well as local class variables. Let's review in detail:
The variables
height
andpower
are fields of the class and are accessible anywhere within the class.The variable
minutesToSleep
is only accessible within the local scope of the block of code in which it's declared.The variable
minutesToRun
is only accessible within the local scope of the block of code in which it's declared.
The scope of a variable limits its accessibility by definition. However, class fields are accessible outside of the class and can be used by any other block of code.
In the example, those are height
and power
. If you declare a unicorn variable, you can read or alter those values:
Unicorn firefly = new Unicorn();
Console.WriteLine("I know it's height: " + unicorn.height);
// and can change its power!
unicorn.power = 0; // no fun!
Being able to mess around with class variables can have serious consequences. The good news is - you can control that! Before we check out how, be sure to practice with variable scoping.
Try it out for yourself!
Ready to get started? To access the exercise, click this link.
Access control
We are going use the idea of access control by implementing restricted access to a class or assembly. You already know what a class is since we’ve been working with them!
An assembly is a compiled code library used for deployment, versioning, and security. It is a collection of classes and resources that are built to work together and form a logical unit of functionality. There are a number of assemblies provided with the .NET Framework. The implementation of those assemblies is far beyond what the developers who use them can see and utilize. That’s done by restricting access to the details of implementation, also known as access control.
Access levels
In C#, you use one of the keywords to designate an access level:
Public: Visible to the world and therefore the least restrictive.
Protected: Visible to the package and all its subclasses.
Internal: Typically visible only to the package they are in.
Private: Only accessible in the context in which they are defined (inside the class it is located).
Putting those distinct restrictions in place makes the development a lot easier. You don't have to worry about any unwanted visibility of your implementation and more so, unwanted modifications.
Place a suitable keyword in front of the related declaration:
class Unicorn
{
// properties
private int height = 170;
public string power = "Double.infinity";
// methods
private void Sleep()
{}
public void Run()
{}
}
Then, if you try to access private members from outside of the class, you get errors:
Unicorn unicorn = new Unicorn();
Console.WriteLine(unicorn.power); // Ok
unicorn.height = 180; // Error
unicorn.Sleep(); // Error
unicorn.Run(); // Ok
The access levels can be assigned to class elements as well as classes:
public class PublicClass {
}
private class PrivateClass {
}
In addition to security, specifying access levels for class members provides better readability. When a developer is readying a source file, it's always clear which elements can be used externally.
Let's recap!
In this chapter, you've learned about variable accessibility:
A scope of a variable is the code area where it's been declared.
General variable scope applies to all code blocks, including classes.
Another necessary way to control access to variables and functions is using access levels:public, protected, internal, and private.