C# Constructors and MSIL Code Explosion

C# offers a very convenient syntax to initialize type level members. You can declare and initialize type level members in a one line expression as shown below

public class Exploded
    {
        int x1 = 10;

 

While this is great for writing clean expressive code I wondered how and what point the members actually get initialized. For example if I declare a class with a member initialization as above with three different constructors that can be independently used by a consumer of my class to instantiate an object of the class, how does the .NET runtime ensure that this variable declared above is initialized and ready for consumption when an object of my class is instantiated?

So I loaded up IL DASM and I noticed what looked like a “code explosion” in the MSI! It turns out the CSC compiler takes a very interesting “code duplication” approach to initialize type level members.
Consider the following code

public class Exploded
{
int x1 = 10;
int x2 = 30;
string s1 = "hey";
string s2;
string s3 = "hi";
string s4 = "hwy";
string s5 = "me";

public Exploded()
{

}

public Exploded(string s1)
{

}

}

 

If you examine the MSIL generated by this code you would notice that the code to initialize members x1, x2, s3, s4 and s5 has been in lined by the compiler in both of the constructors offered by the class! The MSIL that displays the constructors looks like this


Double click both the constructors one by one and you would notice the same pattern that shows in-line initialization for the type level members

Think back to the modules you have designed in the past that initialized type members using the convenient syntax. That initialization logic was in-lined by the CSC compiler within each constructor that your type defined.

The “Clean Way”

So obviously the question then is what can we do to reduce this apparent code explosion in the generated MSIL? Before we go from this point onwards, let me make it clear that in all of the tests that I ran I did not notice any performance degradation whatsoever due to this code duplication within MSIL. The only concern that I have here which prompted me to write this post was that this code duplication taken across all the types in a component and all the components in a product might add a considerable bloat to the file size of the shipped product. It is that which I am trying to save here. Well that and the fact that it is nice to look under the hood and understand how things work 
So back to the discussion, one clean way to manage this would be to have your initialization logic in-lined in one constructor and setup a chain so that each constructor ultimately calls into that one base constructor. Consider this code

public class Managed
{
int x1;
int x2;
string s1;
string s2;
string s3;
string s4;
string s5;

public Managed()
{
x1 = 10;
x2 = 30;
s1 = "hey";

s3 = "hi";
s4 = "hwy";
s5 = "me";
}

public Managed(string s1)
: this()
{

}

public Managed(string s1, string s2)
: this(s1)
{

}

public Managed(string s1, string s2, string s3)
: this(s1, s2)
{

}

 

Here I have setup one base constructor which does the field initialization and then all other constructors roll up to this one constructor.

public Managed(string s1, string s2)
: this(s1)

 

Calls the base constructor directly whereas

public Managed(string s1, string s2, string s3)
: this(s1, s2)

Calls the second overloaded constructor which then calls the first constructor. If you examine the MSIL as generated by this code below, you would notice that all the duplicated initialization statements are now gone!


So what about types with no explicit constructor?
For any such type that does not offer an explicitly defined constructor, CSC compiler adds a default constructor in the generated MSIL. Consider the class below

public class NoConstructor
{
int x1 = 10;
}

 

If you examine the MSIL generated for this class, you would observe that a default constructor was added to this class and further the initialization logic was in-lined in this constructor as per the explanation given above.


I have zipped up the code used in this sample which is available for download here

As a final note I would like to point your attention to an innocuous looking flag “beforefieldinit” that appears in the MSIL (seen picture above). As my journey into the world of constructors and MSIL went further I realized just how bad this flag can impact the performance of a component. This post is available here
 

Leave a Comment

Your email address will not be published.

1 Trackback

  1. Nik's Corner – C# Type Constructors and Performance (Pingback)