Reader Question: Member Initializers vs. Constructors

I received a very interesting question from a reader earlier this week:

I have a question for you about Item 12 in Effective C# (2nd edition), "Prefer Member Initializers to Assignment Statements".  Here is my problem:

I recently inherited a very complicated application in which I had to find and fix a bug.  It was incredibly painful.  The application contained many classes that contained other classes that contained other classes that inherited from other classes that inherited from other classes.  I think you get the idea.  I found the member initializers particularly painful.  When code was about to create a new object, and I'd expect to step into its constructor, instead I'd end up stepping through a maze of member initializers for other classes, with no idea where I was, or why I was there, before I'd get to the constructor of the class I expected to be in.

After that experience, I swore that I would not use member initializers ever, and always initialize members in my constructors, so that when stepping through the code there would be some sense of chronological order of object creation that made sense.

Item 12 tells me to prefer member initializers.  You give 2 reasons why: to minimize the risk of omitting an initialization with multiple constructors, and to initialize variables as early in time as possible.  I guess my question is why is it important to initialize variables as early in time as possible???  I'd like to purposely delay initialization until I'm in the constructor to help debugging seem more natural, but if there is a real benefit of initializing earlier, I'd rather do that.  Are there any memory use or compiler optimization benefits to using member initializers?

This is a great question, because it does highlight language features, coding practices, and tools.

First the language features: the C# designers made the decision that variables in an object are initialized before any code in that object executes. You can initialize a variable with a field initializer, or accept the default initialization of the 0 bit pattern. That means field initializers execute before any constructor code. As I wrote in Effective C#, initializing object fields using field initializers insures that all are definitely initialized as early as possible.

I recommended initializing fields as early as possible, because it minimizes the chance of null reference exceptions. If you initialize fields before any code executes, you cannot write code that accesses those fields before you initialize the fields. The more code (even in constructors) that you may execute before initializing fields, the more likely you introduce those kinds of bugs. As code bases grow, developers may add new constructors, or add new method calls in constructors. Any of those additions can dereference unitialized fields, causing bugs. I expand on this in C# Puzzlers, where I discuss virtual method calls in constructors.

However, this coding practice can make it hard to debug.  There’s a little-known feature that really helps:  You can set breakpoints on field initializers. It can be confusing, unless you remember the order of initialization. That’s why I went into extensive detail in Effective C# on the initialization order of objects created using C# (and interacting with VB.NET, where the order is different).  It can be somewhat tricky, especially with very deep hierarchies. But, hopefully, you have to debug initialization code less often.

Finally, note that the title says “Prefer Field Initializers”. It’s not an absolute rule: some fields are much more naturally initialized using constructors. But, absent good reason to pull the code into a constructor, the field initializer is preferred.

Created: 7/25/2012 8:59:01 PM

Current Projects

I create content for .NET Core. My work appears in the .NET Core documentation site. I'm primarily responsible for the section that will help you learn C#.

All of these projects are Open Source (using the Creative Commons license for content, and the MIT license for code). If you would like to contribute, visit our GitHub Repository. Or, if you have questions, comments, or ideas for improvement, please create an issue for us.

I'm also the president of Humanitarian Toolbox. We build Open Source software that supports Humanitarian Disaster Relief efforts. We'd appreciate any help you can give to our projects. Look at our GitHub home page to see a list of our current projects. See what interests you, and dive in.

Or, if you have a group of volunteers, talk to us about hosting a codeathon event.