#789 – Grouping Constants into Their Own Class

Constants are declared as class members.  They are effectively static, since there is not a different value for each instance of the class, but you declare them without using the static keyword.

You can use a constant in the class in which it is defined, referring to it by name.  You can also use the constant in other classes, prefixing the name of the constant with the class name.

You can define a constant within a class that contains related data and methods.  It’s also a common practice to group a number of constants into their own class, which is used solely to contain a collection of constants.

    public class Constants
    {
        public const double Pi = 3.14159265358979;
        public const double GoldenRatio = 1.61803398874;
        public const string MNReply = "Not so bad";
    }

Now we can use the constants as follows:

            Console.WriteLine("Pi = {0}", Constants.Pi);

#586 – Default Values for Optional Parameters Must Be Constants

When you specify a default value for an optional parameter, that value must be a constant, of the same type as the parameter.  The expression must be able to be evaluted at compile-time.  The parameter’s default value can be one of the following:

  • A constant expression (see below)
  • new S(),  where S is a value-type (parameters not allowed on constructor)

A constant expression is one that can be fully determined at compile-time.  In other words, you can use any expression that you’d use in the initialization of a constant.

For reference types, the expression must be null, with the exception of the string type.

        private const int OFFSET = 1;

        static void Optional1(int x = 5 + OFFSET, double y = 1.0/3.0) { }
        static void Optional2(Point3D fln = new Point3D()) { }
        static void Optional3(Dog d = null) { }
        static void Optional4(string s = "DEFAULT") { }

        static void Main()
        {
            Optional1();
            Optional2();
            Optional3();
        }

#338 – Static Readonly Fields vs. Constants

A static readonly field in a class is very similar to a constant.  Both expose a constant, static value that is associated with the class, independent of any instances of the class.

We could declare a static readonly field in a Dog class:

        public static readonly string TheDogMotto = "Man's Best Friend";

We could also declare this value as a constant:

        public const string TheDogMotto = "Man's Best Friend";

The value of a constant must be known at compile-time and specified as part of the declaration.

The value of a static readonly field is set at run-time, so it can be different from run to run.  It is specified in either the declaration or within a static constructor.

Use a readonly field for values that you won’t know until run-time or have to calculate.  Use a constant for values that are known and never change.

#321 – Accessibility of Constants

As with other class members, you can apply access modifiers to constants defined in a class to define their accessibility.  Accessibility dictates what other code has access to the constant’s value.

  • public – All code has access
  • private – Only code in the defining class has access
  • protected – Code in the defining class or derived classes has access
  • internal – All code in the defining assembly has access
  • protected internal – Code in the defining assembly or in derived classes has access
        // All code has access
        public const string PluralOfDog = "Dogs";

        // Only this class has access
        private const Breeds DefaultBreed = Breeds.Retriever;

        // Subclass has access
        protected const string DefaultDogName = "Bowser";

        // Code in same assembly has access
        internal const string TargetArchitecture = "x86";

        // Code in same assembly or subclass has access
        protected internal const int DeckSize = 52;

#320 – The Constant Expression for a Reference-Typed Constant Must Be Null

The declaration of a constant may use a reference type as the type of the constant.  However, reference types other than string are seldom seen.  The compiler needs to evaluate the value of the constant at compile time.  This means that the constant expression cannot invoke a method on a reference type.  The only valid value in the expression is therefore null.

            // Marginally useful
            const Dog TheNullDog = null;

            // Not allowed - Compile-time ERROR
            const Dog ConstantBob = new Dog("Bob");

One exception to this rule about only using null in a constant expression for a reference type is the string (System.String) class.  A constant of type string may be initialized with a string literal.

            // string constants can be initialized, although they are reference types
            const string MyDogsName = "Kirby";

#319 – You Initialize a Constant Using an Expression

You initialize a constant in C# using either a literal or an expression that resolves to the correct type.

    public class Dog
    {
        const string Demeanor = "friendly";
        const int NumberOfLegs = 4;
        const double OneThird = 1.0 / 3.0;

You can also use the value of another constant in a constant expression.

        const int NumberOfLegs = 4;
        const int NumberOfEyes = 2;
        const int EyeAndLegCount = NumberOfLegs + NumberOfEyes;

The constant expression must be able to be resolved at compile time, so you can’t use something that is not a constant.  This includes variables and also includes the results of method calls.

        static int NumLegs = 4;   // Not a constant

        // Error: The expression being assigned to 'ConsoleApplication2.Dog.LegsPlusOne' must be constant
        const int LegsPlusOne = NumLegs + 1;

#318 – You Can’t Use the static Modifier On a Constant

Although constants can be treated as static member variables, you cannot include the static keyword when declaring a constant.  A constant is always effectively static, so the static keyword would be redundant.  The compiler will generate an error if you include it.

        // This is ok
        const string Demeanor = "friendly";

        // !! Compiler error - constant cannot be marked static
        static const int TheAnswer = 42;