Variables are a powerful tool, but there are times when you want to manipulate a defined value, one whose value you want to ensure remains constant. A constant is like a variable in that it can store a value. However, unlike a variable, you cannot change the value of a constant while the program runs.
For example, you might need to work with the Fahrenheit freezing
and boiling points of water in a program simulating a chemistry
experiment. Your program will be clearer if you name the variables that
store these values FreezingPoint
and
BoilingPoint
, but you do not want to
permit their values to be changed while the program is executing. The
solution is to use a constant. Constants come in three flavors:
literals, symbolic constants , and enumerations .
A literal constant is just a value. For example, 32 is a literal constant. It does not have a name; it is just a literal value. And you can’t make the value 32 represent any other value. The value of 32 is always 32. You can’t assign a new value to 32, and you can’t make 32 represent the value 99 no matter how hard you might try.
Symbolic constants assign a name to a constant value. You declare a symbolic constant using the following syntax:
consttype identifier = value;
The const
keyword is followed
by a type, an identifier, the assignment operator (=
), and the value with which you’ll
initialize the constant.
This is similar to declaring a variable, except that you start
with the keyword const
and symbolic
constants must be initialized. Once
initialized, a symbolic constant cannot be altered. For example, in
the following declaration, 32 is a literal constant and FreezingPoint
is a symbolic constant of type
int
:
const int FreezingPoint = 32;
Example 3-4 illustrates the use of symbolic constants.
Example 3-4. Using symbolic constants
class Values
{
static void Main( )
{
const int FreezingPoint = 32; // degrees Fahrenheit
const int BoilingPoint = 212;
System.Console.WriteLine("Freezing point of water: {0}",
FreezingPoint );
System.Console.WriteLine("Boiling point of water: {0}",
BoilingPoint );//BoilingPoint = 21;
}
}
Example 3-4
creates two symbolic integer constants: FreezingPoint
and BoilingPoint
. See the sidebar, "Naming Conventions,”
for a discussion of how to name symbolic constants.
These constants serve the same purpose as using the literal values 32 and 212 for the freezing and boiling points of water, respectively, in expressions that require them. However, because the constants have names, they convey far more meaning. It might seem easier to just use the literal values 32 and 212 instead of going to the trouble of declaring the constants, but if you decide to switch this program to Celsius, you can reinitialize these constants at compile time to 0 and 100, respectively, and all the rest of the code should continue to work.
To prove to yourself that the constant cannot be reassigned, try un-commenting the last line of the preceding program by removing the two slash marks:
BoilingPoint = 21;
When you recompile, you receive this error:
The left-hand side of an assignment must be a variable, property or indexer
Enumerations provide a powerful alternative to literal or simple symbolic constants. An enumeration is a distinct value type, consisting of a set of named constants (called the enumerator list).
In Example 3-4, you created two related constants:
const int FreezingPoint = 32; const int BoilingPoint = 212;
You might want to add a number of other useful constants to this list as well, such as:
const int LightJacketWeather = 60; const int SwimmingWeather = 72; const int WickedCold = 0;
Notice, however, that this process is somewhat cumbersome; also, this syntax shows no logical connection among these various constants. C# provides an alternate construct, the enumeration, which allows you to group logically related constants, as in the following:
enum Temperatures { WickedCold = 0, FreezingPoint = 32, LightJacketWeather = 60, SwimmingWeather = 72, BoilingPoint = 212, }
Many programmers like to leave a comma after the last entry in an enumeration as a convenience for adding more values later. Other programmers find this, at best, sloppy. The code will compile either way.
The complete syntax for specifying an enumeration uses the
enum
keyword, as follows:
[attributes
] [modifiers
]enum
identifier
[:
base-type
]{
enumerator-list
};
In a specification statement like the preceding example,
anything in square brackets is optional. Thus, you can declare an
enum
with no attributes,
modifiers, or base-type.
The optional attributes and modifiers are considered later in
this book. For now, let’s focus on the rest of this declaration. An
enumeration begins with the keyword enum
, which is generally followed by an
identifier; in this case, Temperatures
:
enum Temperatures
The base-type is the underlying type for the enumeration. You
might specify that you are declaring constant int
s, constant long
s, or something else. If you leave out
this optional value (and often you will), it defaults to int
, but you are free to use any of the
integral types (ushort
, long
) except for char. For example, the
following fragment declares an enumeration with unsigned integers
(uint
) as the base-type:
enum ServingSizes : uint { Small = 1, Regular = 2, Large = 3 }
Notice that an enum
declaration ends with the enumerator list, which contains the constant
assignments for the enumeration, each separated by a comma. Example 3-5 rewrites Example 3-4 to use an
enumeration.
Example 3-5. Using an enumeration
class Values { // declare the enumeration enum Temperatures { WickedCold = 0, FreezingPoint = 32, LightJacketWeather = 60, SwimmingWeather = 72, BoilingPoint = 212, } static void Main( ) { System.Console.WriteLine("Freezing point of water: {0}", (int) Temperatures.FreezingPoint ); System.Console.WriteLine("Boiling point of water: {0}", (int) Temperatures.BoilingPoint ); } }
In Example 3-5,
you declare an enumerated constant called Temperatures
. When you want to use any of
the values in an enumeration in a program, the values of the
enumeration must be qualified by the enumeration name.
You cannot just refer to FreezingPoint
; instead, you use the
enumeration identifier (Temperature
) followed by the dot operator
and then the enumerated constant (FreezingPoint
). This is called
qualifying the identifier FreezingPoint
. Thus, to refer to the
FreezingPoint
, you use the full
identifier Temperature.FreezingPoint
.
You might want to display the value of an enumerated constant to the console, as in the following:
Console.WriteLine("The freezing point of water is {0}", (int) Temperature.FreezingPoint);
To make this work properly, you must cast the constant to its
underlying type (int
). When you
cast a value, you tell the compiler “I know that
this value is really of the indicated type.” In this case, you are
saying, “Treat this enumerated constant as an int
.” Because the underlying type is
int
, this is safe to do. (See the
sidebar, "Casting.”)
In Example 3-5,
the values in the two enumerated constants FreezingPoint
and BoilingPoint
are both cast to type integer;
then that integer value is passed to WriteLine( )
and displayed.
Each constant in an enumeration corresponds to a numerical value. In Example 3-5, each enumerated value is an integer. If you don’t specifically set it otherwise, the enumeration begins at 0 and each subsequent value counts up from the previous. Thus, if you create the following enumeration:
enum SomeValues { First, Second, Third = 20, Fourth }
the value of First
will be 0,
Second
will be 1, Third
will be 20, and Fourth
will be 21.