7

I wonder if object initializing have some performance gain in ASP.NET website. I have an office mate that told me that object initialization is much readable and faster than constructor. But one of my office mate disagree with that and said that it always depends. For example I am doing this:

using (var dataAccess = new DatabaseAccess { ConnectionString = ConfigurationManager.ConnectionStrings["test"].ConnectionString, Query = query, IsStoredProc = true })
{
    //some code here
}

Is it better if I will do this way?

using (var dataAccess = new DatabaseAccess())
{
    dataAccess.ConnectionString = ConfigurationManager.ConnectionStrings["test"].ConnectionString;
    dataAccess.Query = query;
    dataAccess.IsStoredProc = true;
}

Thanks in advance guys!

---EDIT----

is this somehow much better:

using (
    var dataAccess = new DatabaseAccess 
    {
        ConnectionString = ConfigurationManager.ConnectionStrings["test"].ConnectionString,
        Query = query,
        IsStoredProc = true
    }
)
{
    //some code here
}
JRC
  • 173
  • 1
  • 6
  • I agree with the it depends. Both may have their usages in different situations. As far as the argument for speed goes. Surely that is such a trivial thing (for most cases) to almost be pointless wasting your breath on? I personally don't think your edit is any better btw – dreza Jun 16 '13 at 07:41

2 Answers2

23

Stop!

You have a bigger problem than the readability. It looks like you don't understand how object initializers work.

Let's create a disposable class which traces its execution:

public class Demo : IDisposable
{
    private string hello;

    public Demo()
    {
        Debug.WriteLine("The parameterless constructor was called.");
    }

    public Demo(string hello)
        : this()
    {
        Debug.WriteLine("The constructor with parameters was called.");
        this.Hello = hello;
    }

    public string Hello
    {
        get
        {
            Debug.WriteLine("The getter was called.");
            return this.hello;
        }

        set
        {
            Debug.WriteLine("The setter was called.");
            this.hello = value;
            throw new NotImplementedException();
        }
    }

    public void Dispose()
    {
        Debug.WriteLine("The disposer was called.");
    }
}

Now, let's write an app which initializes this class in three different ways (sorry, it's too big; I'll explain it more in details later):

public static class Program
{
    // --- Interesting stuff ---
    private static void WithPropertiesInitialization()
    {
        using (var demo = new Demo())
        {
            demo.Hello = "Hello World!";
            // Do nothing.
        }
    }

    private static void WithObjectInitializer()
    {
        using (var demo = new Demo { Hello = "Hello World!" })
        {
            // Do nothing.
        }
    }

    private static void WithConstructor()
    {
        using (var demo = new Demo("Hello World!"))
        {
            // Do nothing.
        }
    }

    // --- Not so interesting stuff ---
    public static void Main()
    {
        Debug.Listeners.Add(new TextWriterTraceListener(Console.Out));

        Console.WriteLine("With constructor:");

        try
        {
            WithConstructor();
        }
        catch (NotImplementedException)
        {
        }

        Console.WriteLine();
        Console.WriteLine("With object initializer:");

        try
        {
            WithObjectInitializer();
        }
        catch (NotImplementedException)
        {
        }

        Console.WriteLine();
        Console.WriteLine("With properties initialization:");

        try
        {
            WithPropertiesInitialization();
        }
        catch (NotImplementedException)
        {
        }

        Console.WriteLine();
        Console.WriteLine("Press any key to continue...");
        Console.ReadKey(true);
    }
}

There are three types of initialization here:

  • Through the constructor, the value to set to the property being passed to the constructor,
  • With the usage of an object initializer,
  • With a parameterless constructor, the property being assigned later.

Before continuing to read the answer, ask yourself two questions:

  • Do those initialization techniques result in the same console output?
  • Is there a bug?

Those techniques are totally different, and there is effectively two bugs: only one of them is correct.

1. Constructor

using (var demo = new Demo("Hello World!"))
{
    // Do nothing.
}

has nothing wrong, but it's the actual implementation of the constructor which is wrong. Constructors shouldn't throw exceptions, and one of the reasons is that it may cause inconsistent state when the object is used inside a using block: it's not fully initialized yet, so it will not be disposed, causing disaster if the unfinished initialization allocated some resources which should have been disposed.

using (var a = new A())
{
    DoWork(a);
}

is basically the same as:

var a = new A();
try
{
    DoWork(a);
}
finally
{
    a.Dispose();
}

As you can see, there is no try around the constructor, so an exception within it would terminate the program before reaching a.Dispose(): in all cases, we can't invoke a method of an object which is not initialized yet.

The setter of Hello throws an exception; the constructor should have been using the backing field directly, instead of the property.

2. Object initializer

    using (var demo = new Demo { Hello = "Hello World!" })
    {
        // Do nothing.
    }

is itself incorrect, and if you have used Code Analysis even at Minimum Recommended Rules level, you would have seen the warning CA2000, telling that:

object '<>g__initLocal0' is not disposed along all exception paths.

What it that?!

That is the indicating that somewhere, an object is created and not disposed. To avoid concurrency issues, when you use an object initializer, a temporary instance of created:

this.Pet = new Gremlin
{
    Title = "Mogwai",
    Age = 14,
}

is transformed by the compiler into:

Gremlin someCrypticName = new Gremlin();
someCrypticName.Title = "Mogwai";
someCrypticName.Age = 14;
this.Pet = someCrypticName;

Indeed, when you use an object initializer inside a using (...):

  • The temporary object is created,
  • The properties are assigned,
  • The temporary object is assigned to the one which is used inside a using,
  • The using block runs.

Any exception thrown when assigning properties will prevent disposing the object, since the assignment happens before the try/finally.

3. Late assignment

using (var demo = new Demo())
{
    demo.Hello = "Hello World!";
    // Do nothing.
}

is correct. Since the constructor is not expected to throw an exception (and if it will, it would be the fault of the person who implemented the constructor, not the person who is using it within the using), all exceptions will occur within the try block, resulting in the demo object being properly disposed.

Conclusion:

using should contain either:

  • A parameterless constructor,

  • A constructor which takes parameters,

given that constructors are not expected to throw exceptions.

using should not contain an object initializer: properties should be initialized within the using { ... }, in order to guarantee the proper disposal of objects.

Readability

Now that you've understood that the two pieces of code in your question are totally difference, since one is correct, and another one is buggy, let's talk readability.

Until C# 4.0, object initialization was slightly more readable than a similar constructor:

var product = new Product("PowerEdge R620 rack server", 1, "Intel® Xeon® E5-2620", 16, 1929, true);

Here, I have no idea what is "1" or "16" or "1929". A person who is not at all familiar with hardware wouldn't know what "Intel® Xeon® E5-2620" is. No one would find what is true.

Instead:

var product = new Product
{
    Title = "PowerEdge R620 rack server",
    RackUnits = 1,
    ProcessorName = "Intel® Xeon® E5-2620",
    MemoryInGB = 16,
    PriceInDollars = 1929,
    IsAvailable = true,
}

is much more readable.

.NET Framework introduced named arguments, and since then, a constructor can be as readable as an object initializer, while being more compact. For example, title is explicit enough, and we would consider that anyone will understand the names of processors, so we can write:

var product = new Product(
    "PowerEdge R620 rack server",
    "Intel® Xeon® E5-2620",
    rackUnits: 1,
    memoryInGB: 16,
    priceInDollars: 1929,
    isAvailable: true);

I have an office mate that told me that object initialization is much readable and faster than constructor.

We have seen that with named arguments, a constructor can be as readable as an object initializer. What about performance?

Above, I've explained that an object initializer this.a = new A { B = b } is translated by the compiler into:

A temp = new A();
temp.B = b;
this.a = temp;

If the only thing the constructor is doing is to assign fields or properties from arguments, then the performance would be approximately the same. Unless your office mate can give precise profiling results and benchmarks proving his point, his statement about the performance should be considered wrong.

Ghost4Man
  • 115
  • 1
  • 4
Arseni Mourzenko
  • 134,780
  • 31
  • 343
  • 513
  • explained perfectly! thanks for clearing things MainMa! – JRC Jun 16 '13 at 10:51
  • 11
    I disagree. Constructors *should* throw exceptions if you're trying to initialize the class to an invalid state. Which is exactly the same situation when setters should throw an exception. – svick Jun 16 '13 at 11:09
  • 1
    Also, a nitpick: .Net 4.0 didn't introduce named parameters, C# 4.0 did. (As far as I know, VB already had them for a long time then.) – svick Jun 16 '13 at 11:11
  • @svick: about exceptions, what about code contracts? Setters are more complicated, because they can *bring an existent object* into an invalid state or be used in a case where the object is not ready to process the setter. – Arseni Mourzenko Jun 16 '13 at 14:53
  • 1
    @svick: changed the answer to C# 4.0. Thank you. I always mix C#, .NET Framework and Visual Studio when it comes to versions. – Arseni Mourzenko Jun 16 '13 at 15:03
  • +10 (Though SE makes you settle for +1) Thanks for a great concise yet comprehensive tutuorial on this subject. – Marjan Venema Jun 16 '13 at 15:06
  • Constructors not protected against exceptions? Wow. This is a huge mental shift for someone coming from Delphi, where an exception thrown in a constructor automatically results in the destructor being called and the var which would have received the reference guaranteed to be nil. – Marjan Venema Jun 16 '13 at 15:13
  • @MarjanVenema: I wasn't clear. Technically, you can throw exceptions from constructors and finalizers (read "destructors", even if in C#, destructors and finalizers don't refer to the same thing) will be called anyway. Just that it's not the best practice to throw an exception in the constructor. One of the drawbacks is that it will cause issues in `using`s, like I've illustrated above. – Arseni Mourzenko Jun 16 '13 at 15:35
  • Ah ok. Yes, I agree that it is not a best practice, in C# or in Delphi. – Marjan Venema Jun 16 '13 at 15:42
  • Two things: (1) you should rarely if ever use the backing field instead of the property, regardless of whether it is in the constructor or not. With auto properties you don't even have a choice about that. (2) It should not be likely, but when the constructor fails, it should definitely throw an exception. Otherwise you are just asking for a random bug elsewhere. – jmoreno Jun 16 '13 at 18:28
  • Very good explanation. Also useful to remember that using may not work if the ctor of a 3rd party class that you don't control throws an exception. Then your only option is a try{..}finally{..} – softveda Jun 17 '13 at 11:11
  • @jmoreno: I disagreed with your second statement, believing that Code analysis will generate a warning if an exception is thrown in a constructor, but actually, I was wrong: CA1065 forbids exceptions in property get methods, *static* constructors, finalizers, etc., but not in instance constructors. I was wrong. So thank you for your comment. – Arseni Mourzenko Jul 02 '13 at 15:08
  • 3
    So maybe we can settle the constructor/exception debate with, that in case a constructor throws an exception in any case, it should throw it before allocating resources which need to be `Dispose()`d. In case it does throw the exception after allocation, the constructor would need to `Dispose()` the resources before throwing the exception (maybe even requiring a `try {} catch{}`). But for simplicity sake, it is strongly recommended to avoid throwing exceptions after allocating resources - if possible. – BatteryBackupUnit Jul 03 '14 at 07:38
1

The first snippet you posted isn't less readable because it uses initialization - it's less readable because it's poorly written. Each initialization assignment should have its own line (unless there's only one assignment, or the initialization block is very short.)

As for performance, I would be very surprised if the first snippet compiled differently than the second one, but I'm not 100% on that.

  • please see my edit. – JRC Jun 16 '13 at 05:03
  • @Otome: *"I would be very surprised if the first snippet compiled differently than the second one"*: it *is* compiling differently, since it creates a temporary variable. But performance-wise, it means just that an object initializer might be a few microseconds slower than a constructor, which really doesn't matter. – Arseni Mourzenko Jun 16 '13 at 09:31