55

How can I initialize a const / static array of structs as clearly as possible?

class SomeClass
{

    struct MyStruct
    {
        public string label;
        public int id;
    };

    const MyStruct[] MyArray = {
          {"a", 1}
          {"b", 5}
          {"q", 29}
    };
};

5 Answers 5

56

Firstly, do you really have to have a mutable struct? They're almost always a bad idea. Likewise public fields. There are some very occasional contexts in which they're reasonable (usually both parts together, as with ValueTuple) but they're pretty rare in my experience.

Other than that, I'd just create a constructor taking the two bits of data:

class SomeClass
{

    struct MyStruct
    {
        private readonly string label;
        private readonly int id;

        public MyStruct (string label, int id)
        {
            this.label = label;
            this.id = id;
        }

        public string Label { get { return label; } }
        public string Id { get { return id; } }

    }

    static readonly IList<MyStruct> MyArray = new ReadOnlyCollection<MyStruct>
        (new[] {
             new MyStruct ("a", 1),
             new MyStruct ("b", 5),
             new MyStruct ("q", 29)
        });
}

Note the use of ReadOnlyCollection instead of exposing the array itself - this will make it immutable, avoiding the problem exposing arrays directly. (The code show does initialize an array of structs - it then just passes the reference to the constructor of ReadOnlyCollection<>.)

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

19 Comments

@Chris: No, I'd say it goes far beyond just publicly consumable APIs. How big is your team? Are you always going to work for that company? How sure are you that every member of your team, now and forever, understands the many and varied oddnesses of mutable structs? For throwaway code, I'd agree... but most code lives much longer in maintenance mode than we originally expect, and poor design can make it much harder to disentangle that later on. You find that someone's passed a field by reference and then you can't refactor to properties without breaking it, etc.
It is a shame that there is so much extra typing here. In C++11 I can do: struct foo { int i; const char* str; char c; }; foo f[] = { { 1, "hello", 'c' }, { 2, "goodbye", 'd'" }}; It would be nice if one didn't need to write the constructor or have to type "new foo" so much.
@Jon Skeet: I have a question. Considering that label and id are readonly, is there any reason to allow accessing them only thorugh property instead of let them be public? Does the compiler optimize it, or accessing them through accessor has an overhead respect of accessing them as public fields?
@FifaEarthCup2014: That would leave the properties being writable within the type - which will be fixed in C# 6, fortunately. At the moment, there's no way of writing a truly read-only automatically implemented property.
@Tutankhamen: Again, "I've shown the OP how to create and initialize an array" - what do you think the code: new[] { new MyStruct ("a", 1), new MyStruct ("b", 5), new MyStruct ("q", 29) } does? It initializes an array.
|
29

Are you using C# 3.0? You can use object initializers like so:

static MyStruct[] myArray = 
            new MyStruct[]{
                new MyStruct() { id = 1, label = "1" },
                new MyStruct() { id = 2, label = "2" },
                new MyStruct() { id = 3, label = "3" }
            };

2 Comments

With C# 3 you don't need the () for each constructor call (as you're using an object initializer) and you can ditch the "new MyStruct[]" bit as that's implied anyway due to being the initializer for an array variable.
To be clear, despite appearances and the lack of "new" this will still allocate an array on the heap, not the stack.
7

You cannot initialize reference types by default other than null. You have to make them readonly. So this could work;

    readonly MyStruct[] MyArray = new MyStruct[]{
      new MyStruct{ label = "a", id = 1},
      new MyStruct{ label = "b", id = 5},
      new MyStruct{ label = "c", id = 1}
    };

2 Comments

Note that that only makes the variable readonly - it doesn't prevent other code from replacing elements in the array.
This solution worked for me. It's a shame that we don't have something as dense and efficient as old C-style array/struct initializers.
3

Change const to static readonly and initialise it like this

static readonly MyStruct[] MyArray = new[] {
    new MyStruct { label = "a", id = 1 },
    new MyStruct { label = "b", id = 5 },
    new MyStruct { label = "q", id = 29 }
};

Comments

-3

I'd use a static constructor on the class that sets the value of a static readonly array.

public class SomeClass
{
   public readonly MyStruct[] myArray;

   public static SomeClass()
   {
      myArray = { {"foo", "bar"},
                  {"boo", "far"}};
   }
}

1 Comment

An access modifier is not allowed for static constructors

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.