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?
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?
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.
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.
Initializer blocks are GREAT practice for the following reasons:
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
The parameter-less constructor can still do things behind the scene (e.g. initialize state members).
You can use in conjunction with constructors with parameters
this.ObjA = new ObjA(20)
{
Name = "123",
};
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.
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.
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:
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).
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.
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.
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.