Variables
You declare variables in C# using the following
syntax:
For example:
This statement declares an int named i. The compiler
won’t actually let you use this variable until you have initialized
it with a value, but the declaration allocates 4 bytes on the stack
to hold the value.
Once it has been declared, you can assign a value
to the variable using the assignment operator, =:
You can also declare the variable and initialize
its value at the same time:
This syntax is identical to C++ and Java syntax but
very different from Visual Basic syntax for declaring variables. If
you are coming from Visual Basic 6, you should also be aware that
C# doesn’t distinguish between objects and simple types, so there
is no need for anything like the Set
keyword, even if you want your variable to refer to an object. The
C# syntax for declaring variables is the same no matter what the
data type of the variable.
If you declare and initialize more than one
variable in a single statement, all of the variables will be of the
same data type:
To declare variables of different types, you need
to use separate statements. Don’t assign different data types
within a multiple variable declaration:
Notice the // and the
text after in the preceding examples. These are comments. The
// character sequence tells the compiler
to ignore the text that follows. Comments in code are further
explained later in this chapter.
Initialization of Variables
Variable initialization demonstrates another
example of C#’s emphasis on safety. Briefly, the C# compiler
requires that any variable be initialized with some starting value
before you refer to that variable in an operation. Most modern compilers will flag violations
of this as a warning, but the ever-vigilant C# compiler treats such
violations as errors. This prevents you from unintentionally
retrieving junk values from memory that is left over from other
programs.
C# has two methods for ensuring that variables are
initialized before use:
-
Variables that are fields in a class or
struct, if not initialized explicitly, are by default zeroed out
when they are created.
-
Variables that are local to a method must be
explicitly initialized in your code prior to any statements in
which their values are used. In this case, the initialization
doesn’t have to happen when the variable is declared, but the
compiler will check all possible paths through the method and will
flag an error if it detects any possibility of the value of a local
variable being used before it is initialized.
C#’s approach contrasts with that of C++, in which
the compiler leaves it up to the programmer to make sure that
variables are initialized before use, and that of Visual Basic, in
which all variables are zeroed out automatically.
For example, you can’t do the following in C#:
Notice that this code snippet demonstrates defining
Main() so that it returns an
int instead of void.
When you attempt to compile these lines, you will
receive this kind of error message:
The same rules apply to reference types as well.
Consider the following statement:
In C++, this line would create an instance of the
Something class on the stack. In C#,
this same line of code would only create a reference for a Something
object, but this reference does not yet actually refer to any
object. Any attempt to call a method or property against this
variable would result in an error.
Instantiating a reference object in C# requires use
of the new keyword. You create a
reference as shown in the previous example and then point the
reference at an object allocated on the heap using the new keyword:
Variable Scope
The scope of a
variable is the region of code from which the variable can be
accessed. In general, the scope is determined by the following
rules:
-
A field (also known
as a member variable) of a class is in scope for as long as its
containing class is in scope (this is the same as for C++, Java,
and VB).
-
A local variable is
in scope until a closing brace indicates the end of the block
statement or method in which it was declared.
-
A local variable that is declared in a
for, while,
or similar statement is in scope in the body of that loop. (C++
developers will note that this is the same behavior as the ANSI
standard for C++. Early versions of the Microsoft C++ compiler did
not comply with this standard but scoped such variables to remain
in scope after the loop terminated.)
Scope Clashes for Local Variables
It’s common in a large program to use the
same variable name for different variables in different parts of
the program. This is fine as long as the variables are scoped to
completely different parts of the program so that there is no
possibility for ambiguity. However, bear in mind that local
variables with the same name can’t be declared twice in the same
scope, so you can’t do this:
Consider the following code sample:
This code simply prints out the numbers from 0 to
9, and then back again from 9 to 0, using a for loop. The important thing to note is that you
declare the variable i twice in this
code, within the same method. You can do this because i is declared in two separate loops, so each
i variable is local to its own loop.
Here’s another example:
If you try to compile this, you’ll get an
error:
This occurs because the variable j, which is defined before the start of the
for loop, is still in scope within the
for loop, and won’t go out of scope
until the Main() method has finished
executing. Although the second j (the
illegal one) is in the loop’s scope, that scope is nested within
the Main() method’s scope. The compiler
has no way to distinguish between these two variables, so it won’t
allow the second one to be declared. This, again, is different from
C++, where variable hiding is permitted.
Scope Clashes for Fields and Local Variables
In certain circumstances, however, you can
distinguish between two identifiers with the same name (although
not the same fully qualified name) and the same scope, and in this
case the compiler will allow you to declare the second variable.
The reason is that C# makes a fundamental distinction between
variables that are declared at the type level (fields) and
variables declared within methods (local variables).
Consider the following code snippet:
This code will compile, even though you have two
variables named j in scope within the
Main() method: the j that was defined at the class level, and doesn’t
go out of scope until the class is destroyed (when the Main() method terminates, and the program ends); and
the j defined in Main(). In this case, the new variable named
j that you declare in the Main() method hides the
class-level variable with the same name, so when you run this code,
the number 30 will be displayed.
However, what if you want to refer to the
class-level variable? You can actually refer to fields of a class
or struct from outside the object, using the syntax object.fieldname. In the previous example, you are
accessing a static field (you look at what this means in the next
section) from a static method, so you can’t use an instance of the
class; you just use the name of the class itself:
If you were accessing an instance field (a
field that belongs to a specific instance of the class), you would
need to use the this keyword instead.
This keyword performs the same role as this in C++ and Java, and Me in Visual Basic.
Constants
Prefixing a variable with the const keyword when it is declared and initialized
designates that variable as a constant. As the name implies, a
constant is a variable whose value cannot be changed throughout its
lifetime:
Constants will be familiar to Visual Basic and C++
developers. C++ developers should, however, note that C# does not
permit all the subtleties of C++ constants. In C++, not only could
variables be declared as constant, but depending on the
declaration, you could have constant pointers, variable pointers to
constants, constant methods (that don’t change the contents of the
containing object), constant parameters to methods, and so on.
These subtleties have been discarded in C#, and all you can do is
declare local variables and fields to be constant.
Constants have the following characteristics:
-
They must be initialized when they are
declared, and once a value has been assigned, it can never be
overwritten.
-
The value of a constant must be computable at
compile time. Therefore, you can’t initialize a constant with a
value taken from a variable. If you need to do this, you will need
to use a readonly field (this is explained in Chapter
3, “Objects and Types”).
-
Constants are always implicitly static.
However, notice that you don’t have to (and, in fact, are not
permitted to) include the static
modifier in the constant declaration.
At least three advantages exist to using constants
in your programs:
-
Constants make your programs easier to read
by replacing magic numbers and strings with readable names whose
values are easy to understand.
-
Constants make your programs easier to
modify. For example, assume that you have a SalesTax constant in one of your C# programs, and
that constant is assigned a value of 6 percent. If the sales tax
rate changes at a later point in time, you can modify the behavior
of all tax calculations simply by assigning a new value to the
constant; you don’t have to hunt throughout your code for the value
.06 and change each one, hoping that
you’ve found all of them.
-
Constants make it easier to avoid mistakes in
your programs. If you attempt to assign another value to a constant
somewhere in your program other than at the point where the
constant is declared, the compiler will flag the error.
|