views:

262

answers:

7

Hi I use initializer block in C#

new Something { foo = 1, bar = 2 };

but people say this is bad practice.

I don't think it is wrong, is it?

+2  A: 

but people say is bad practice.

Who says this? At the very least, that’s a controversial statement.

It seems to be all the rage at the moment, and many prominent C# blogs use it extensively.

The advantage over using a constructor is that it’s more readable since the code clearly shows which properties get assigned what values. Compare:

var x = new Something { Foo = 1, Bar = 2 };

with

var x = new Something(1, 2);

Furthermore, if no appropriate constructor is present, the code is more concise than manually assigning to properties:

var x = new Something();
x.Foo = 1;
x.Bar = 2;

Personally, I prefer immutable objects (i.e. objects that, once created, cannot be changed). Unfortunately, the initializer blocks cannot be used in conjunction with such objects (at the moment) because to make this pattern work the object has to have property setters, which an immutable object doesn’t have.

But as long as the object used isn’t immutable I don’t see a compelling reason against using the initializer notation.

Konrad Rudolph
C# 4 allows constructor calls to look quite like object initializers - see my post for an example.
Jon Skeet
@Jon It’s nice that C# 4 finally introduces this. Interestingly, the same feature in VB gets very rarely used, although VB.NET had it since the beginning … I wonder why.
Konrad Rudolph
@Konrad: You can get your name fixed if you wish. :) http://meta.stackoverflow.com/questions/45208/possible-feature-request-revert-a-display-name-change-within-24-hours
missingfaktor
@Rahul G: Thanks so much. Although I loved that name. ;-)
Konrad Rudolph
A: 

I think it's good.

Because it reduces your typing a lot

Ngu Soon Hui
Actually, using an appropriately overloaded constructor would be *less* typing. However, using initializers is clearly more *readable* than using a constructor.
Konrad Rudolph
Typing is almost *never* the limiting factor in programming. Code for readability, not reduced typing.
Jon Skeet
+1  A: 

There is nothing wrong with initializer blocks, but if your type for example has many properties, and only a couple of them need to be set on every instance, then you should make them required in a constructor.

The user of your class will know that they can't create an object without specifying those values.

Brian R. Bondy
+2  A: 

Initializer blocks are GREAT practice for the following reasons:

  1. You get to create an object and override its properties before getting its reference

    this.ObjA = new ObjA
    {
        Age = 20,
        Name = "123",
    };
    
    
    // this.ObjA will not be set until properties have all been defined
    // - safer when multithreading
    
  2. The parameter-less constructor can still do things behind the scene (e.g. initialize state members).

  3. You can use in conjunction with constructors with parameters

    this.ObjA = new ObjA(20)
    {
        Name = "123",
    };
    
  4. Using parameter-less constructors is better for (de)serializing scenarios

    You can create various objects, change their state via GUI, serialize them, deserialize them elsewhere.

  5. This practice forces authors to write more robust code - where the order in which things are done is less lightly to cause the application to crash every time the class's metadata is changed.

Danny Varod
On the other hand, it forces the type to be mutable... I certainly wouldn't say they're "great" practice. They're useful when you've already got mutable state, but I still prefer immutable state set in a constructor.
Jon Skeet
Objects with immutable states do not have settable properties, so initializer blocks are not an option for them.
Danny Varod
+5  A: 

It's questionable (I won't say "bad") practice to use initialization blocks as a substitute for the appropriate constructor overload, if one exists.

public class Entity
{
    public Entity()
    {
    }

    public Entity(int id, string name)
    {
        this.ID = id;
        this.Name = name;
    }

    public int ID { get; set; }
    public string Name { get; set; }
}

If you have this very simple class, then it is generally preferable to write:

var entity = new Entity(1, "Fred");

...than it is to write:

var entity = new Entity { ID = 1, Name = "Fred" };

There are at least two good reasons for this:

  1. You don't know exactly what the constructor is doing. It's possible that, in some circumstances, it might be significantly more expensive to construct the object and then set public properties vs. passing the values through the constructor itself. (You may know that this is not the case, but as the consumer of a class, you shouldn't presume to know care about the implementation details, because they are subject to change).

  2. Your code won't break if one or more of those properties have their names changed, or become read-only (which the ID probably should have been in the first place, but perhaps wasn't due to architectural constraints like that of an ORM).

However, there is one case where you have to use initializers instead of overloaded constructors, and that is when chaining selects in a Linq to SQL/EF query:

var bars =
    from f in ctx.Foo
    select new Bar { X = f.X, Y = f.Y };
var bazzes =
    from b in bars
    select new Baz { ... };

This can actually fail with a "no supported mapping" if you use constructor overloads instead of default constructors + initializers. This is, however, a constraint of the technology being used (and an undesirable one at that), and not a coding style issue.

In other cases, you should prefer the constructor overload over the initializer.

If there is no useful/relevant constructor overload that can do the same thing as your initializer, then go ahead and write the initializer, there's nothing wrong with it. The feature exists for a good reason - it makes the code easier to write and read.

Aaronaught
Does this happen much? I can't remember the last time I saw a complex/expensive constructor, or had a core property change significantly (in a way my editor couldn't trivially fix). I read code with object constructors all the time and want to know what their parameters mean.
Ken
@Ken: WCF clients (`ClientBase<T>`) are one example of objects that are expensive to construct. Lots of classes I write will perform default initialization tasks in the default constructor. While I don't disagree with you with respect to readability, it's also important to realize that initializers are just syntactic sugar for property setters (i.e. `var x = new MyClass(); x.ID = 1; x.Name = "Fred";`), which simply does not have the same semantics as supplying those values to the constructor.
Aaronaught
A: 

The properties that are essential for the object work, should be initialized in the constructor, so you should provide the appropiate parameters in hthe contstructor.

Initializer blocks are very handy for several of the new features of C# 3.0, but you should keep in mind, that they are not here for replace the parameters in the constructor.

vtortola
+2  A: 

You need to ask yourself whether your type should be mutable or not. Personally, I like immutable types - they make it easier to reason about what's going on, easier to validate (once the constructor has been called and the state validated, you know it's not going to become invalid) and they're great for concurrency.

On the other hand, object initializers are certainly useful in cases where it is reasonable to have mutable types. As an example, ProcessStartInfo is effectively used as a builder type for Process. It's useful to be able to write:

var info = new ProcessStartInfo { 
    FileName = "notepad.exe",
    Arguments = "foo.txt",
    ErrorDialog = true
};
Process process = Process.Start(info);

Indeed, you can even do all this inline instead of having an extra variable. My Protocol Buffers port uses the same sort of pattern:

Foo foo = new Foo.Builder { 
    FirstProperty = "first",
    SecondProperty = "second"
}.Build();

Now one alternative to the builder pattern is constructor parameters (possibly via factory methods). The historical downside of this is that you needed different overloads depending on which properties were being set, and if several parameters had the same type it could be hard to tell which was which. C# 4 makes this significantly easier using optional parameters and named arguments. For example, if you're building an email class you could have:

Email email = new Email(
    from: "[email protected]",
    to: "[email protected]",
    subject: "Test email",
    body: textVariable
);

This has many of the same benefits of object initializers in terms of clarity, but without the mutability penalty. The constructor call above may have missed out some optional parameters such as attachments and a BCC list. I think this will prove to be one of the biggest benefits of C# 4 for those of us who like immutability but also like the clarity of object initializers.

Jon Skeet
Interesting aside; the SO syntax highlighter is thinking that 'from' is a keyword (presumably from support for highlighting LINQ.)
Dan Bryant