Initializing an Array of Structs in C#
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 }
};
Adam Tegen
Updated on July 09, 2022Comments
-
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 over 15 yearsWith 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 over 15 yearsNote that that only makes the variable readonly - it doesn't prevent other code from replacing elements in the array.
-
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 about 12 yearsAwesome John, you just made me realize a new angle of modern object oriented programming. Thank you..
-
Bklyn almost 11 yearsIt 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 almost 11 yearsThis 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 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 over 10 yearsAn access modifier is not allowed for static constructors
-
kiss my armpit almost 10 yearsSorry. 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 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 over 9 yearsSupposing I go down this route, and considering this'll mean I'm required to write a constructor, are there any benefits to making
MyStruct
astruct
rather of aclass
? -
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 about 9 yearsTo be clear, despite appearances and the lack of "new" this will still allocate an array on the heap, not the stack.
-
Tutankhamen over 8 yearsList and Array are two different things
-
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 over 8 yearsyes I did and this is why I wrote about your answer here.
-
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 over 8 yearsExactly! You didn't show how to initialize an ARRAY and this is what I objecting to.
-
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 over 8 years@JonSkeet what would be the best way to implement a constructor with a struct that conatins pointers?
-
Jon Skeet over 8 years@Kyle: I never use pointers myself. I suggest you ask a new question with appropriate details.
-
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 about 5 yearsStating 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 about 5 years@BryanW.Wagner: Have reworded this.