Initializing an Array of Structs in C#

145,940

Solution 1

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

Solution 2

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

Solution 3

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

Solution 4

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 }
};
Share:
145,940
Adam Tegen
Author by

Adam Tegen

Updated on July 09, 2022

Comments

  • Adam Tegen
    Adam Tegen almost 2 years

    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}
        };
    };
    
  • Jon Skeet
    Jon Skeet over 15 years
    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.
  • Jon Skeet
    Jon Skeet over 15 years
    Note that that only makes the variable readonly - it doesn't prevent other code from replacing elements in the array.
  • Jon Skeet
    Jon Skeet about 13 years
    @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.
  • Adarsha
    Adarsha about 12 years
    Awesome John, you just made me realize a new angle of modern object oriented programming. Thank you..
  • Bklyn
    Bklyn almost 11 years
    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.
  • David Jeske
    David Jeske almost 11 years
    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.
  • Heisenbug
    Heisenbug almost 11 years
    @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?
  • Philipp M
    Philipp M over 10 years
    An access modifier is not allowed for static constructors
  • kiss my armpit
    kiss my armpit almost 10 years
    Sorry. Why didn't you simplify the code by replacing the read only fields and associated read only properties just with read only automatic properties?
  • Jon Skeet
    Jon Skeet almost 10 years
    @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.
  • antak
    antak over 9 years
    Supposing I go down this route, and considering this'll mean I'm required to write a constructor, are there any benefits to making MyStruct a struct rather of a class?
  • Jon Skeet
    Jon Skeet over 9 years
    @antak: You sure use a struct if you want it to be a value type - which usually means it should be reasonably small, and treated as a value - something like a number or a date/time value.
  • yoyo
    yoyo about 9 years
    To be clear, despite appearances and the lack of "new" this will still allocate an array on the heap, not the stack.
  • Tutankhamen
    Tutankhamen over 8 years
    List and Array are two different things
  • Jon Skeet
    Jon Skeet over 8 years
    @Tutankhamen: Indeed - did you read to the end of my answer? "Note the use of ReadOnlyCollection instead of the array itself - this will make it immutable, avoiding the problem exposing arrays directly." My answer does create an array, but then wraps it in a read-only collection (which isn't a List either, btw).
  • Tutankhamen
    Tutankhamen over 8 years
    yes I did and this is why I wrote about your answer here.
  • Jon Skeet
    Jon Skeet over 8 years
    @Tutankhamen: I've shown the OP how to create and initialize an array - and also explained why exposing that array directly is a bad thing, and that wrapping it up in a read-only collection is a better idea. The OP is presumably satisfied, given that they accepted the answer... I don't see what you're objecting to.
  • Tutankhamen
    Tutankhamen over 8 years
    Exactly! You didn't show how to initialize an ARRAY and this is what I objecting to.
  • Jon Skeet
    Jon Skeet over 8 years
    @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.
  • DotNet Programmer
    DotNet Programmer over 8 years
    @JonSkeet what would be the best way to implement a constructor with a struct that conatins pointers?
  • Jon Skeet
    Jon Skeet over 8 years
    @Kyle: I never use pointers myself. I suggest you ask a new question with appropriate details.
  • DotNet Programmer
    DotNet Programmer over 8 years
    @JonSkeet ok I thought I would just ask since you typically have the best answers and why not ask one of the best on here at giving detailed answers.
  • Bryan W. Wagner
    Bryan W. Wagner about 5 years
    Stating that mutable structs or public fields are "evil" assumes a lot about the context in which they're used, and using the word "evil" is dogmatic.
  • Jon Skeet
    Jon Skeet about 5 years
    @BryanW.Wagner: Have reworded this.