524
votes

Is it possible to write something similar to the following?

public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
15
static could be used, public static string[] Titles = new string[] { "German", "Spanish"};Ray

15 Answers

788
votes

Yes, but you need to declare it readonly instead of const:

public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

The reason is that const can only be applied to a field whose value is known at compile-time. The array initializer you've shown is not a constant expression in C#, so it produces a compiler error.

Declaring it readonly solves that problem because the value is not initialized until run-time (although it's guaranteed to have initialized before the first time that the array is used).

Depending on what it is that you ultimately want to achieve, you might also consider declaring an enum:

public enum Titles { German, Spanish, Corrects, Wrongs };
67
votes

You can declare array as readonly, but keep in mind that you can change element of readonly array.

public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";

Consider using enum, as Cody suggested, or IList.

public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
66
votes

You can't create a 'const' array because arrays are objects and can only be created at runtime and const entities are resolved at compile time.

What you can do instead is to declare your array as "readonly". This has the same effect as const except the value can be set at runtime. It can only be set once and it is thereafter a readonly (i.e. const) value.

24
votes

Since C# 6 you can write it like:

public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };

See also: C# : The New and Improved C# 6.0 (specifically the chapter "Expression Bodied Functions and Properties")

This will make a read-only static property, but it will still allow you to alter the content of the array returned, but when you call the property again, you will get the original, unaltered array again.

For clarification, this code is the same as (or actually a shorthand for):

public static string[] Titles
{
    get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}

Please note that there is a downside to this approach: A new array is actually instantiated on each and every reference, so if you are using a very large array, this might not be the most efficient solution. But if you re-use the same array (by putting it in a private attribute for instance) it will again open up the possibility to change the contents of the array.

If you want to have an immutable array (or list) you could also use:

public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };

But, this still has a risk for changes, as you can still cast it back to a string[] and alter the contents, as such:

((string[]) Titles)[1] = "French";
21
votes

This is the only correct answer. You cannot currently do this.

All the other answers are suggesting using static read-only variables which are similar to, but not the same as a constant. A constant is hard coded into the assembly. A static read only variable is settable once, probably as an object is is initialized.

These are sometimes interchangeable, but not always.

EDIT: I thought I'd throw this in, as it seem like the person who asked the question was a little fuzzy about arrays. When you declare an array, it is a pointer to a segment of memory that contains the array. It is very simple in that it is just an address, with no complex logic controlling if it is readable or writable. It gives you a pointer, and you can do whatever you want with it.

This is part of the reason why it is a little tricky to make an immutable array. You could write a class that wraps the array and only allows reading of it by returning a copy, but then it really isn't just an array anymore.

Some people have suggested using static, or readonly to simulate the behavior you would see if you could create const array. These have some side effects that might not be obvious to the casual reader.

To truly get a const array, there would need to be an update to C# and the MSIL underlying code to allow reading from an array, but no writing.

11
votes

A .NET Framework v4.5+ solution that improves on tdbeckett's answer:

using System.Collections.ObjectModel;

// ...

public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
  new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);

Note: Given that the collection is conceptually constant, it may make sense to make it static to declare it at the class level.

The above:

  • Initializes the property's implicit backing field once with the array.

    • Note that { get; } - i.e., declaring only a property getter - is what makes the property itself implicitly read-only (trying to combine readonly with { get; } is actually a syntax error).

    • Alternatively, you could just omit the { get; } and add readonly to create a field instead of a property, as in the question, but exposing public data members as properties rather than fields is a good habit to form.

  • Creates an array-like structure (allowing indexed access) that is truly and robustly read-only (conceptually constant, once created), both with respect to:

    • preventing modification of the collection as a whole (such as by removing or adding elements, or by assigning a new collection to the variable).
    • preventing modification of individual elements.
      (Even indirect modification isn't possible - unlike with an IReadOnlyList<T> solution, where a (string[]) cast can be used to gain write access to the elements, as shown in mjepsen's helpful answer.
      The same vulnerability applies to the IReadOnlyCollection<T> interface, which, despite the similarity in name to class ReadOnlyCollection, does not even support indexed access, making it fundamentally unsuitable for providing array-like access.)
10
votes

If you declare an array behind an IReadOnlyList interface you get a constant array with constant values that is declared at runtime:

public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };

Available in .NET 4.5 and higher.

9
votes

You could take a different approach: define a constant string to represent your array and then split the string into an array when you need it, e.g.

const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');

This approach gives you a constant which can be stored in configuration and converted to an array when needed.

7
votes

For the sake of completeness, now we also have ImmutableArrays at our disposal. This should be truly immutable:

public readonly static ImmutableArray<string> Tiles = ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });

Requires System.Collections.Immutable NuGet reference

https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx

5
votes

For my needs I define static array, instead of impossible const and it works: public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

5
votes

This is a way to do what you want:

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}

It is very similar to doing a readonly array.

3
votes

I believe you can only make it readonly.

3
votes

Arrays are probably one of those things that can only be evaluated at runtime. Constants must be evaluated at compile time. Try using "readonly" instead of "const".

1
votes

As an alternative, to get around the elements-can-be-modified issue with a readonly array, you can use a static property instead. (The individual elements can still be changed, but these changes will only be made on the local copy of the array.)

public static string[] Titles 
{
    get
    {
        return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
    }
}

Of course, this will not be particularly efficient as a new string array is created each time.

1
votes

Best alternative:

public static readonly byte[] ZeroHash = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };