14
votes
\$\begingroup\$

Question: What are peoples preferences between the two methods of creating an object (in C# in particular) and setting other fields (that may not be given values during construction)? Are either of them considered best practice? or is it down to the programmer and any styling conventions in place at the company?

My preference is absolutely for the object initializer method. It looks much cleaner and more concise to me.

Object initializer

Type T = new Type(Param1, Param2)
{
    Field1 = Value1,
    Field2 = Value2,
    Field3 = ValueFromFunction()    
};

Constructor

Type T = new Type(Param1, Param2);
T.Field1 = Value1;
T.Field2 = Value2;
T.Field3 = ValueFromFunction();
\$\endgroup\$

locked by Jamal Jun 30 '14 at 15:13

This question exists because it has historical significance, but it is not considered a good, on-topic question for this site so please do not use it as evidence that you can ask similar questions here. This question and its answers are frozen and cannot be changed. See the help center for guidance on writing a good question.

Read more about locked posts here.

  • \$\begingroup\$ As a mostly java developer I find it confusing that lazy and standard is considered as styles. I figure that this is because there's something C# provides that I'm not familiar with that changes the context from which this question should be read. In my understanding - lazy refers to an optimization strategy that defers the creation of expensive resources to the point of time they are actually needed and preferabely never. However, lazy strategy may come with a run-time penalty if everything is deferred instead of preparing things in advance. \$\endgroup\$ – Aleksi Yrttiaho Aug 23 '11 at 10:27
  • \$\begingroup\$ As I said at the top of my post, I didn't really know what to call either of those. They both do the same job (building an object and setting values in fields), so I elected to refer to them simply as "styles" of doing the job. \$\endgroup\$ – Andy Hunt Aug 23 '11 at 10:37
  • \$\begingroup\$ After some reading, I've edited my post to remove the reference to Java. I remembered initializing objects in a similar way to the one documented above, but didn't realise it wasn't strictly the same thing. \$\endgroup\$ – Andy Hunt Aug 23 '11 at 10:57
  • 2
    \$\begingroup\$ Your code examples are not doing the same things, the second one has Param1, Param2, where the first version does not have these values at all and therefore the two are constructing different objects which would assumably have different purposes. If they are supposed to be functionaly identical, I would put Value1 and Value2 into the Param1/Param2 slots, or else add Param1/Param2 to the initializer example so they can be comparable. \$\endgroup\$ – Jimmy Hoffa Aug 23 '11 at 12:28
  • \$\begingroup\$ I forgot to add the params to my first example when I edited the second. \$\endgroup\$ – Andy Hunt Aug 23 '11 at 13:36
11
votes
\$\begingroup\$

These are both techniques born of different goals.

The constructor style is something you will design your classes for when you want them to be faux-immutable, that is, you do not want them changed after construction so you make the setters on your properties protected or private.

The initializer style comes from you ceding control of the object's data members to the object's consumer, which you will do when you do not care about the order or timeliness of them being filled in.

One of the largest decision making factors here is this: Is the object safely usable if the properties are null?

If not, the constructor format allows you to ensure they will never be null by requiring them be set at construction by parameter and disallowing them to be set by the consumer.

Example of this would be a connection string object, without a database catalog it cannot be safely used as anything that attempted to use it would try to use the database catalog and may throw an exception if it is null.

The other reason for the constructor format vs. initialization is dependencies, this falls into the same question as null safety but can be thought about a little differently: If an object is useless without a particular dependency object or piece of data, then there is little reason to allow its construction without that parameter.

Example of this would be a file stream, if you do not give it a path or some way of knowing about a file, it becomes a useless object.

Edit: All that said, as far as using initializer syntax when available, it's really just sugar and I think everyone can agree that you should use it if you know a number of values at construction time.

\$\endgroup\$
3
votes
\$\begingroup\$

The method you call here "constructor" is not the proper "constructor way" to initialize an object. That said, by my experience, most if not all people prefer initialization by constructor, but I mean not the one shown by you. The constructor should take the values for initialization as parameters, like this:

Type T = new Type(Value1, Value2, ValueFromFunction());

This is what most prefer. It is even preferred over object initializers, unfortunately, not all types have constructors, and some could but are not under your control. In those cases Object initilaizers in C# is a nice syntax.

\$\endgroup\$
  • \$\begingroup\$ I knew there was something I was missing from my constructor example, thankyou. I did mean to include parameters on the constructor, as well as the setting of some other fields. \$\endgroup\$ – Andy Hunt Aug 23 '11 at 11:20
3
votes
\$\begingroup\$

A little late to this party, but I would add that debugging the 'Object initializer' style is difficult using Visual Studio (VS 2012) but trivial easy using the 'constructor' style. VS only allows a breakpoint on the line that contains new keyword. If you wanted to inspect the value Value2 immediately after the Value1 assignment...good luck. The breakpoint hits on the new but you don't get control back until after the entire initialization completes (here, that's the closing brace }).

Also, if the Value2 assignment throws an Exception for some reason, the stack trace will show the throw as taking place on the line with the new keyword. For a 3 line initialization, may not be a big deal.

But, if you have a 300 line initializer (I have seen this!), then you really have no clue as to where the problem lies.

As both styles are syntactically equivalent I'd go with the style more easily debugged and traced style - #2/ 'constructor' style.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.