701

Is it possible to write something similar to the following?

public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
2
  • static could be used, public static string[] Titles = new string[] { "German", "Spanish"}; Commented May 23, 2014 at 18:07
  • Assuming you're returning a literal array of strings, you may also do: return new String[] { "id", "logic_id" };. Note that { "id", "logic_id" } by itself wouldn't be an array or collection; it’s only valid inside an initializer after new. Now you could turn this into a getter, e.g.: public String[] primaryKeyNames { get { return new String[] { "id", "logic_id" }; } } Commented Sep 25 at 9:48

16 Answers 16

979

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 };
Sign up to request clarification or add additional context in comments.

7 Comments

Note that the array here isn't readonly, of course; Titles[2]="Welsh"; would work just fine at runtime
You probably want it static too
how about declaring a "const" array in a method body, not in the class one?
This won't help when you ABSOLUTELY need a const, such as with switch statement cases.
string isn't a char[], see the source. Strings can be consts in C# because the compiler will replace all references to the const with the actual string literal itself.
|
101

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.

2 Comments

This post highlights why arrays cannot be declared as constants
It is possible to declare a constant array; the problem is initializing it with a constant value. The only working example that comes to mind is const int[] a = null; which is not very useful, but indeed an instance of an array constant.
90

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 initialized.

These are sometimes interchangeable, but not always.

EDIT: I thought I'd throw this in, as it seems 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, it is an object that wraps an array.

Some people have suggested using static, or read-only, to simulate the behavior you would see if you could create a const array. These have some side effects that might not be obvious to the casual reader. Also, if you mark an array with read-only, you are marking the pointer to the array, not the array itself. You can change the contents of the array as much as you want:

public class Demo
{
    private readonly int[] _foo = new int[] {0,1,2,3};
    
    public void ChangeArray()
    {
        _foo[1] = 42; // works
        _foo = new int[] { 0, 1, 2, 3, 5 }; // won't even compile
    }
}

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. The other proposals on this page are various creative ways to work around this problem.

2 Comments

Thank you. I was wondering why the most upvoted solutions weren't working for default parameters.
one thing you can do to make it truly* read only is IEnumerable<int> _foo = new int[] {0,1,2,3}.AsEnumerable(); *not truly but virtually
74

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();

2 Comments

In .NET 4.5 and higher you can declare a list as IReadOnlyList<string> instead of IList<string>.
Just to be clear, you can still change the values in an IReadOnlyList (just not add or remove elements). But yes, declaring it as an IReadOnlyList would be better than an IList.
29

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";

4 Comments

What is the profit of using property instead of field in this case?
A field cannot return a new object on each call. A property is basically a sort of "function in disguise".
If you were referring to the last option, that can be done using both a field or a property, but since it is public, I prefer a Property. I never use a public field since the introduction of Properties.
There is another downside to the 1st approach: you won't get a compilation error if you assign to Titles[0], for instance - in effect, the assignment attempt is quietly ignored. Combined with the inefficiency of recreating the array every time, I wonder if this approach is even worth showing. By contrast, the 2nd approach is efficient, and you have to go out of your way to defeat the immutability.
17

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

public readonly static ImmutableArray<string> Titles = ["German", "Spanish", "Corrects", "Wrongs"];

The immutable collections are included in the core .NET libraries.
If you are using .Net Framework, you can use them with the NuGet package System.Collections.Immutable.

3 Comments

I'm not sure when this was added, but ImmutableArray.Create takes in params T[]?, so the code can be simplified to: ImmutableArray.Create("German", "Spanish", "Corrects", "Wrongs").
You can simply further with a collection expression like so: public readonly static ImmutableArray<string> Titles = ["German", "Spanish", "Corrects", "Wrongs"];
The linked documentation says that NuGet are only needed for .NET Framework, which is not recommended by Microsoft. Updating answer to include that and the changes mentioned by the comments.
14

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.)

1 Comment

@mortb: Unfortunately, IReadOnlyCollection doesn't support indexed access, so it can't be used here. Additionally, like IReadOnlyList (which does have indexed access) it is susceptible to element manipulation by casting back to string[]. In other words: ReadOnlyCollection (which you cannot cast a string array to) is the most robust solution. Not using a getter is an option (and I've updated the answer to note that), but with public data it's probably better to stick with a property.
13

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.

Comments

13

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.

2 Comments

I think the cost of performing the split far outstrips any benefits made by defining const. But +1 for a unique approach and thinking outside the box! ;)
I was about to post the same solution and then saw this, contrary to the harsh and negative remarks, this was actually perfect for my scenario, where i needed to pass a const to an Attribute, and then i split the value in attribute constructor to get what i needed. and i see no reason why it will have performance cost since attributes are not created for each instance.
5

I believe you can only make it readonly.

Comments

5

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

3 Comments

Simply removing const from OP example also works, but that (or your answer) allows to change both: Titles instance and any value. So what is the point in this answer?
@Sinatr, I answered this 3 years ago, when I strted working in C#. I left it, now I'm in Java world. Perhaps I forgot to add readonly
After second thought, your answer is a direct how to make OP code working, without any const/readonly considerations, simply making it working (like if const was a syntax mistake). For some people it seems to be a valuable answer (perhaps they also tried to use const by mistake?).
5

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.

1 Comment

You can just do that as public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();; no need to recreate the list on every retrieve if you make it a ReadOnlyCollection anyway.
3

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".

Comments

3

Quick workaround in case it's helpful for someone. I needed a string[] to be an argument for an Attribute (passing inline data for a test case in some theory). readonly won't help here. But, I ended up doing:

const string foo = "a|b|c";

[InlineData(foo)]
public void Test(string fooString)
{
    var foo = fooString.Split("|"); // foo == {"a","b","c"}
    ...
}

Comments

2

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 };

Comments

1

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.