C# 3.0 Object Initializers

Published 13 August 07 08:59 AM

As I'm sure you are aware, C# 3.0 includes a new language feature called object initializers.  Put simply, object initializers enable you to initialize the state of an object with a single expression that does not require use of parameterized constructors.  A few million examples on the object initializer syntax ranging from the simple to complex are out there on the Internet, so there's no need for me to go into them here.  I do, however, want to make a couple of quick points.

1.  The object initializer syntax sits on top of the standard C# language - and it does not allow you to break the basic OO rules of the language.  It feels to me like many of the language features coming down the pipe (at least for both C# 2 and 3) have their real value when taken in groups.  For example, while a cool feature, anonymous methods didn't shine quite so brightly until used in conjunction with generic delegates and the type inference capabilities of C# 2.0 (obviously, lambda expressions are the latest incarnation of this capability).  Similarly, object Initializers seem to have their most value when used in conjunction with anonymous types - and more specifically, when used with anonymous types in the context of a LINQ projection operation.

That said, object initializers should not be thought of as a way to side-step basic object heuristics (and from the implementation perspective, the C# compiler won't let you).  For example, a basic tenant of OO design specifies that an object should be ready to use after constructed.  As a result, many classes are designed such that there are no parameterless constructors (since the result would yield a class that still required initialization after the object was constructed).  In this case, you must call a parameterized constructor even when using the object initializer syntax.  It is worth pointing out, however, that the object initializer syntax is quite handy here in eliminating a lot of "shortcut constructors" from the code base.  The constructor code can require only the parameters that are absolutely necessary to construct the object, while the object initializer syntax can be relied on for allowing the user to provide additional state to the constructed object.

Just in case you hadn't heard yet, this new language feature (and all of the other C# 3.0 features) were implemented without requiring any changes to the IL.  Let's take a look, then, at an example of the syntax and the code generated by the compiler.

Customer jenn = new Customer("default",0) { Name = "jennifer", Age = 31 };

When the project is built and the assembly is reverse engineered, we can see that the generated code is as follows.

private static void Main(string[] args)
{
    Customer <>g__initLocal0 = new Customer("default", 0);
    <>g__initLocal0.Name = "jennifer";
    <>g__initLocal0.Age = 0x1f;
    Customer jenn = <>g__initLocal0;
}

We can see here that our parameterized constructor was called as it has always been, the constructed object is assigned to a temporary variable, our additional properties specified in the initializer syntax are set, and the reference held by our temporary variable is then assigned to our declared variable.  Pretty straightforward.

2.  Be cautious of using object initializers with value types.  I have a real love-hate feeling for language features like this.  On the one hand, they can make life easier and code cleaner.  On the other hand, they can create a false sense of security if one assumes that the feature behaves the same in all contexts.  Take another look at the generated code.  For reference types, this is absolutely no big deal.  A managed reference has a tiny footprint, and hey - what's one more reference for the GC to track <g>? 

For value types, the story is a little different.  Because you have 2 different variables, this single object initialization will end up consuming at least twice the memory required by the type itself.  In the code shown, this is probably not a big deal.  However, if your value type is a little bigger, and if you're initializing it a few hundred times in a loop, you can see how you could inadvertently increase the footprint of your code.  For the DDD crowd, this is definitely something to be cognizant of - especially if you are using value types to implement value-objects.

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# MSDN Blog Postings » C# 3.0 Object Initializers said on August 13, 2007 12:13 PM:

PingBack from http://msdnrss.thecoderblogs.com/2007/08/13/c-30-object-initializers/

# hasanib said on August 14, 2007 9:16 AM:

Will the compiler be smart enough to wrap classes that implement IDisposable in a try/catch & dispose/throw block to ensure the Dispose method gets called when an exception occurs?

Not the best E.x.:

FileStream fs = new FileStream("foo.txt", FileMode.Create){ Position = -2 };

The code will exception. I would like the compiler to dispose the filestream object for me when an exception occcurs during 'object initialization'.

# Sam Marcuccio said on August 14, 2007 6:02 PM:

Ok Howard, I know we've talked about this in the past...

I agree that an object should be 'ready to use' after construction.  The problem is that I have also found that throwing exceptions from a constructor is problematic (especially in the late-bound scenario, i.e. plugable components)  We can follow the dependency injection idea and provide everything that is needed for construction, but how do we handle bad or missing dependencies?

How do you reconcile these two things?

# hdierking said on August 15, 2007 4:46 PM:

Personally, I don't call services in my constructor since there is a high probability that they will, at some point, raise an exception.  Additionally, it's frankly hard to test without using lots of mock objects.

That said, if you really need to do this kind of thing, dependency injection has worked for me in the past as well - you just shouldn't need to actually call the injected service in the ctor - that would smell funny to me.

Another alternative to injecting services into domain objects would be to use the observer pattern in conjunction with an application controller or workflow layer.

So in sum, let's see - what am I reconciling - 'Ready to use' objects vs. the risk of errors in the ctor?  In general, I think that if you have factored your objects correctly, you should be able to create a 'ready to use' object without needing to call service code in the ctor.

# Christian Crowhurst said on August 18, 2007 11:26 AM:

Guys, I'm wondering if someone on this thread could explain the rational for why you shouldn't throw an exception in a constructor? I have heard this advise a handful of times over the last 2 years and never got to the bottom of it.

My main problem with this advise is when you combine it with the rule of always ensuring that an object is 'Ready to use'. Taken to the extreme it would mean factory methods (in all the various forms) are the preferred method of construction as they can perform validation on the inputs before calling the constructor. Then there's the problem that implementing factory methods because of this, has a tendency to move validation logic out of instance based methods of the class being constructed.

Anyone??

Thanks

Christian Crowhurst

# hdierking said on August 19, 2007 4:06 PM:

Christian -

I think you got to the heart of the issue when you used the phrase 'Taken to the extreme'.  In my mind, there are some basic heuristics to follow with regard to constructors, and there are some practical, implementation guidelines.  For example, making calls to services from within a constructor is something I consider a bad idea because it is not explicitly understood as a part of the ctor.  In cases where construction of an object is absolutely dependent on an external service, I believe that a factory is completely appropriate.

Additionally, there are implementation guidelines to follow in constructors - such as not calling virtual members from within ctors.  Again, the reason has to do with the intentionality of the class contract (e.g. - you lose some of it).

In either case, I don't think that issue is whether or not to throw exceptions (I think that if you don't validate your params, you are introducing far more risk than throwing exceptions) - I think the issue is more about creating constructors that...well...construct - no more, no less.

# Christian Crowhurst said on August 20, 2007 5:54 PM:

That's how I've often interpreted the advice, I just always had that nagging doubt that maybe I was missing something. It’s reassuring to hear someone else echo my thoughts.

Yes, I think that calling a Service within a constructor sounds like its time to introduce a factory that will perform the construction and call to the service.

Thanks

Christian

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

About hdierking

I am currently the Editor-in-Chief for MSDN Magazine. I joined Microsoft in 2006 as a product planner with the certification team at Microsoft Learning. Prior to that, I spent my career as a developer and later as an architect. My main technology passions include pretty much anything on language theory, agile development, and service-oriented architecture.
Page view tracker