16

Why does the following work?

class A
{
    public int[,] i = { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } };

    static void Main(string[] args)
    {
    }
}

Whereas the following does not?

class A
{
    public const int[,] i = { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } };

    static void Main(string[] args)
    {
    }
}

It does not allow for a const reference type other than string to be assigned anything other than null. Since it's an array (reference) it must be assigned null(?). How would it be initialized if it's constant and null?

3 Answers 3

18

It's part of the language design of C#, if I remember correctly. const is reserved for items that can have their contents deduced at-compile-time, i.e. before (during) the program is even built and then run. All arrays in C# are run-time arrays (their lengths are determined when the program runs, not before then) and thus they cannot be made into const fields. I feel it's a limitation of C#, but that's how they decided to do it.

The reason reference types can be null is that null is a constant value, whereas your initializer (which is made at run-time) is not. null is built into the language, so by that logic its value is always known, all the time (and thus, usable for compile-time reference types).

EDIT:

You should be able to make a static table, though, that will be initialized the moment it is used or needed by any other code:

public static int[,] i = { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } };
       ^ Static Keyword

You can access it like (if it's still in class A):

A.i[0, 1]

I hope that helps you out

To learn more, look at MSDN: http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k(CS0134);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5)&rd=true

EDITEDIT: If you need to rivet the static table to the code and never let anyone change it after it's been initialized, there's the readonly keyword for that purpose:

public static readonly int[,] i = { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } };
       ^ Static ^Readonly Keywords

Keep in mind, it won't stop you from re-assigning things into those slots, but it's about as fixed as C# can give you, save of making a property or returning a new array every time.

Sign up to request clarification or add additional context in comments.

6 Comments

All I can say is wow. It's forcing me to find ways around making constant tables of integers, besides the most obvious.
@user2255673 If you're looking for something like C++'s const * const you won't find it in C#.
@user2255673 Yes, it's quite unfortunate. But, you can make static tables of integers and operate on those, I've edited my answer to show you.
@user2255673 Just be aware there's nothing "constant" about this; any piece of code can replace or change elements willy-nilly.
@ThePhD No no, readonly will only prevent reassigning a completely new int[,] array reference to it. Nothing stops code from executing i[0, 0] = 9999
|
3

It doesn't work because that's the restriction on the const keyword.

From MSDN:

The const keyword is used to modify a declaration of a field or local variable. It specifies that the value of the field or the local variable is constant, which means it cannot be modified.

A constant expression is an expression that can be fully evaluated at compile time. Therefore, the only possible values for constants of reference types are string and null

If you are trying to define an array that can't change, maybe you should use the readonly keyword, which restrict changes being made to a field or local variable to either declaration or in the constructor.

1 Comment

Note that readonly will only make the array reference readonly. The contents are still mutable by index for anybody who has a reference to the array.
2

Constants are evaluated at compile time. Array's are reference types, and the only way to create a reference type is to use the new keyword (which is implicit in your code).

new cannot be used in a constant expression, because it cannot be evaluated at compile time.

See MSDN: http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k(CS0134);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5)&rd=true

2 Comments

Note that strings are a bit of a caveat, as strings are reference types, but have special baked in support for loading them as constants from the underlying IL code.
Indeed, I probably should have mentioned that.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.