Thanks a lot, everyone, for all your comments and feedback on my Five Little Wonders Trilogy of posts. This week, it’s crunch time at my workplace so this post is going to be on the brief side. As I’ve been coding on my latest project, it struck me that there’s at least two things that object/collection initializers can do that you can’t easily do without them.
Refresher on Initializers
For those of you who don’t know or can’t remember, object initializers are when you assign members of a class or struct immediately after construction in the initializer syntax. For example, assuming we had a Point struct with typical X and Y members:
1 : // first constructs Point using default constructor, then assigns X & Y
2 : var p1 = new Point() { X = 3, Y = 10 };
3 : 4 : // this is logically equivalent to:
5 : var p2 = new Point();
6 : p2.X = 3;
7 : p2.Y = 10;
And collection initializers are when you assign the contents of an IEnumerable that contains an Add() method at construction:
1 : // can do with primitives
2 : var listOfInt = new List<int>() { 1, 2, 3, 4, 5 };
3 : 4 : // or combine with object initialization to do complex:
5 : var listOfPoint = new List<Point>() 6 : {
7 : new Point() { X = 1, Y = 2 },
8 : new Point() { X = 5, Y = 7 },
9 : new Point() { X = 0, Y = 0 } 10 :
};
Now, whether you put the curlies on the same line or next line is purely a matter of style and taste for initializers. Object initializers work for any public mutable properties or fields of a class, and collection initializers work for any collection that implements IEnumerable and has an Add() method. So it’s really easy to enable both types of initializers for any types you create as necessary.
So that’s the initializers in a quick refresher nutshell, I didn’t want to delve into too much usage detail as that’s beyond the scope of this particular post. There’s plenty of good nutshell posts, I also cover them briefly in the second of my Five Little Wonders posts here.
The Difference?
Now, many of you may be looking at this and thinking, “yeah, big deal, it’s a syntactical shortcut and no more or no less”. Well, you’re partly right. There are two things I’ve found that can’t be done easily without object initializers. I’m not claiming that they are necessarily impossible, but I can see no way to do it as easily or as cleanly.
So what are these two things?
- Constructing and initializing an anonymous argument to a method.
- Initializing a static member and still maintaining beforefieldinit CIL attribute.
Constructing and Initializing an Anonymous Argument
No, I’m not talking about anonymous types here, but an anonymous argument. That is, being able to construct an argument in the call to a method or property without specifying a variable name.
For example, let’s say we have our mythical Point class and want to construct a new pair of Points to draw a line, we could do something like this:
1 : var first = new Point();
2 : first.X = 3;
3 : first.Y = 7;
4 : 5 : var second = new Point();
6 : second.X = 9;
7 : second.Y = 13;
8 : 9 : DrawLine(first, second);
Obviously, that’s a lot of lines of code for some throw-away points. But now, with initializers, we can easily do:
1: DrawLine(new Point() { X = 3, Y = 7}, new Point() { X = 9, Y = 13});
Now this is a contrived example, to be sure, but notice that we’re constructing an anonymous instance of a Point and immediately assigning the elements in the call to the method. This is something you can’t do well without initializers. Now, to be fair, you could create a constructor that takes the coordinates, but what if you have no control over the class or need to set a property that is not available in the constructor? Before initializers you were out of luck.
I find this extremely handy with collection intializers. For example, I have a JMS messaging abstraction library that hides the underlying JMS implementation from my business layer so I can swap out providers as needed. In that library I define a Message that is a generic abstraction of a JMS message. Besides obviously having a Text property, it has a List<MessageProperties>.
Because of collection initializers, I can easily create a JMS message at the point of sending it and assign the properties using the collection initializer:
1: public void SendHeartbeat()
2: {
3: _jmsSender.Send(new Message("HEARTBEAT")
4: {
5: { "MACHINE", Environment.MachineName },
6: { "TIME", DateTime.Now }
7: });
8: }
Yes, I could have created the object above and then passed the variable into the method call. But there’s really no need since it’s only used once. Without initializers, you can’t anonymously create an argument and initialize it in the call itself. Now, it may boil down to the same CIL in the end, but in terms of C# code (and VB.NET too) it can really reduce the amount of clutter.
Initializing a Static Member While Preserving BeforeFieldInit
The beforefieldinit CIL attribute is applied to most classes or structs that do not have a static constructor. For those who don’t know, a static constructor is a constructor in a class or struct that has no access modifier, takes no parameters, and has the keyword static in front of it.
For example, it used to be that if you had a class with a static collection member, you would have to initialize it in a static constructor like so:
1 : public class NotBeforeFieldInit
2 : {
3 : public static List<int> ThisList = new List<int>();
4 : 5 : static NotBeforeFieldInit() 6 : {
7 : ThisList.Add(1);
8 : ThisList.Add(2);
9 : ThisList.Add(3);
10 : ThisList.Add(4);
11 : ThisList.Add(5);
12:
}
13:
}
Now, this looks very innocent, but it turns out whenever you have an explicit static constructor, the C# compiler will not mark the type with the beforefieldinit CIL property.
1: .class public auto ansi NotBeforeFieldInit
2: extends [mscorlib]System.Object
3: {
4: } // end of class NotBeforeFieldInit
So why is this important? Well, the beforefieldinit property controls how the static fields are initialized. If the property is present, it means that the property can be initialized any time before it’s first call. However, if a class has an explicit static constructor, it can’t mark the type with this property because it has to first check and make sure that the static constructor has been run before any static field on the type can be accessed. This means a very slight degradation in performance, as any attempt to access a static field has to do a check to make sure the static constructor has already been called.
So how does an initializer help you here? Oddly enough, it allows you to construct and initialize the object and still preserve the beforefieldinit property of your class, which means better performance as it won’t have to check each call for a static constructor call:
1: public class BeforeFieldInit
2: {
3: public static List<int> ThisList = new List<int>() { 1, 2, 3, 4, 5 };
4: }
Now, using the initializer, we can look at the generated IL:
1: .class public auto ansi beforefieldinit BeforeFieldInit
2: extends [mscorlib]System.Object
3: {
4: } // end of class BeforeFieldInit
As you can see, using the collection initializer we have initialized the static member and we still have our beforefieldinit CIL attribute, which will give us a slight performance edge. And, to boot, I think it’s much more readable.
Summary
So, use those object and collection initializers! They help your code look cleaner and more concise, and in at least one case can actually give you a slight performance edge in your generated CIL!
Technorati Tags: C#,.NET,Initializer,Collection,IEnumerable,static,Object initializer,Collection Initializer