Most of .NET developers are familiar with collection initializers syntax. Long story short, this language feature allows you to replace this ugly syntax
1 2 3 4 5 |
var numbers = new List<int>(); numbers.Add(1); numbers.Add(2); numbers.Add(3); numbers.Add(4); |
with much shorter and cleaner one
1 |
var numbers = new List<int> { 1, 2, 3, 4 }; |
The more interesting thing is the fact that you can leverage this syntax not only for build-in collections but also for your custom classes. In order to do that your class must implement IEnumerable interface and expose public Add method. Let’s assume that we have some real case scenario and we have class which looks like that
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public class StatusMessages : IEnumerable<StatusMessage> { private List<StatusMessage> messages = new List<StatusMessage>(); public IEnumerator<StatusMessage> GetEnumerator() { return this.messages.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return this.messages.GetEnumerator(); } } public class StatusMessage { public string Text { get; set; } = string.Empty; public string SourceSystem { get; set; } = string.Empty; public int StatusCode { get; set; } public StatusMessage() { } public StatusMessage(string text) { this.Text = text; } public override string ToString() { return $"Text: {this.Text} StatusCode: {this.StatusCode} SourceSystem: {this.SourceSystem}"; } } |
This is a simple wrapper over the List
1 2 3 4 5 6 7 8 9 |
public class StatusMessages : IEnumerable<StatusMessage> { // rest of the code omitted for brevity public void Add(StatusMessage message) { this.messages.Add(message); } // rest of the code omitted for brevity } |
we can create a new instance of that class just like we would do with List
1 2 3 4 5 |
var messagesAddInitializer = new StatusMessages { new StatusMessage("y"), new StatusMessage("x"), }; |
What is more, it is possible to have multiple overloads of Add method in our class, so for instance if we add
1 2 3 4 5 6 7 8 9 |
public class StatusMessages : IEnumerable<StatusMessage> { // rest of the code omitted for brevity public void Add(string text) { this.Add(new StatusMessage(text)); } // rest of the code omitted for brevity } |
we are able to use this syntax
1 2 3 4 5 |
var messagesAddStringInitializer = new StatusMessages { "y", "x" }; |
In addition it is even possible to use a mix of Add overloads
1 2 3 4 5 |
var messagesAddAndTextInitializers = new StatusMessages { new StatusMessage("y"), "x" }; |
Add method can also have multiple arguments
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class StatusMessages : IEnumerable<StatusMessage> { // rest of the code omitted for brevity public void Add(int statusCode, string text) { this.Add(new StatusMessage(text) { StatusCode = statusCode }); } public void Add(int statusCode, string text, string sourceSystem) { this.Add(new StatusMessage(text) { StatusCode = statusCode,SourceSystem = sourceSystem }); } // rest of the code omitted for brevity } |
in that case we are able to use this syntax
1 2 3 4 5 |
var messagesMultipleArgumentsInitializers = new StatusMessages { { 1, "x" }, {1,"x","source" } }; |
The last thing I would like to point out is that Add function doesn’t have to be an instance method, we can easily implement it as an extension method and still leverage the collection initializer syntax.
1 2 3 4 5 6 7 8 9 10 |
namespace AbusingCollectionInitializers { public static class StatusMessagesExtensions { public static void Add(this StatusMessages statusMessages, int statusCode) { statusMessages.Add(new StatusMessage() { StatusCode = statusCode }); } } } |
Now with proper namespace import we can write this code
1 2 3 |
using AbusingCollectionInitializers; // rest of the code omitted for brevity var messagesExtensionInitializers = new StatusMessages { 1,2,3 }; |
Source code for this post can be found here