{
private int red;
private int green;
private int blue;
public Color(int red, int green, int blue) {
this.red = red;
this.green = green;
this.blue = blue;
} }
As some colors are used more frequently than others (for example, black and white) we can declare constants for them, with the idea that the users of our class will take them for granted, instead of creating their own objects for these particular colors every time. To do this, we modify the code of our class as follows, adding the declaration of the following color-constants:
Color.cs
class Color {
public const Color Black = new Color(0, 0, 0);
public const Color White = new Color(255, 255, 255);
private int red;
private int green;
private int blue;
public Color(int red, int green, int blue) {
this.red = red;
this.green = green;
this.blue = blue;
} }
Strangely, when we try to compile, we get the following error:
'Color.Black' is of type 'Color'. A const field of a reference
type other than string can only be initialized with null.
'Color.White' is of type 'Color'. A const field of a reference type other than string can only be initialized with null.
This is so because in C#, constants, declared with the modifier
const
, can be only of the following types:1. Primitive types:
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
,bool
.2. Enumerated types (discussed in section "Enumerations" at the end of this chapter).
3. Reference types (mostly the type
string
).The problem with the compilation of the class in our example is connected with the reference types and the restriction on the compiler not to allow simultaneous use of the operator
new
when declaring a constant when this constant is declared with the modifierconst
, unless the reference type can be calculated at compile time.As we can guess, the only reference type, which can be calculated at compile time while using the operator
new
isstring
.Therefore, the only possibilities for reference type constants that are declared with modifier
const
are, as follows:1. The constants must be of type
string
.2. The value, which we assign to the constant of reference type, other than
string
, isnull
.We can formulate the following definition:
Constants declared with modifier
const
must be of primitive, enumeration or reference type, and if they are of reference type, this type must be either astring
or the value, that we assign to the constant, must benull
.Thus, using the modifier
const
, we will not be able to declare the constantsBlack
andWhite
of typeColor
in our color class because they aren’tnull
. The next section will show us how to deal with this problem.Runtime Constants (readonly)
When we want to declare reference type constants, which cannot be calculated during compilation of the program, we must use a combination of
static readonly
modifiers, instead ofconst
modifier.[<access_modifiers>] static readonly <reference-type> <name>;
Accordingly,
<reference-type>
is a type the value of which cannot be calculated at compilation time.The compilation is successful if we replace
const
bystatic readonly
in the last example of the previous section:public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
Naming the Constants
The constants names in C# follow the PascalCase rule according to the Microsoft’s official C# coding convention. If the constant is composed of several words, each new word after the first one begins with a capital letter.
Here are some examples of correctly named constants:
// The base of the natural logarithms (approximate value) public const double E = 2.718281828459045;
public const double PI = 3.141592653589793;
public const char PathSeparator = '/';
public const string BigCoffee = "big coffee";
public const int MaxValue = 2147483647;
public static readonly Color DeepSkyBlue = new Color(0,104,139);
Sometimes naming in style ALL-CAPS is used but it is not officially supported by the Microsoft code conventions, even though it is widely distributed in programming:
public const double FONT_SIZE_IN_POINTS = 14; // 14pt font size
The examples made it clear that the difference betweenconst
andstatic readonly
fields is in the moment of their value assignments. The compile- time constants (const
) must be initialized at the moment of declaration, while the run-time constants (static readonly
) can be initialized at a later stage, for example in one of the constructors of the class in which they are defined.Using Constants
Constants are used in programming to avoid repetition of numbers, strings or other common values (literals) in the program and to enable them to change easily. The use of constants instead of brutally hardcoded repeating values facilitates readability and maintenance of the code and is highly recommended practice. According to some authors all literals other than
0
,1
,-1
, empty string,true
,false
andnull
must be declared as constants, but this can make it difficult to read and maintain the code instead of making it simple. Therefore, it is believed that values, which occur more than once in the program or are likely to change over time, must be declared as constants.In the chapter "High-Quality Programming Code" will we learn in details when and how to use constants efficiently.