Setting properties via object initialization or no

2019-02-05 12:29发布

Here's a simple question : Is there any (performance) difference between this :

Person person = new Person()
{
  Name = "Philippe",
  Mail = "phil@phil.com",
};

and this

Person person = new Person();
person.Name = "Philippe";
person.Mail = "phil@phil.com";

You can imagine bigger object with more properties.

5条回答
该账号已被封号
2楼-- · 2019-02-05 12:39

They are almost exactly equivalent except that the first method (using an object initializer) only works in C# 3.0 and newer. Any performance difference is only minor and not worth worrying about.

They produce almost identical IL code. The first gives this:

.method private hidebysig instance void ObjectInitializer() cil managed
{
    .maxstack 2
    .locals init (
        [0] class Person person,
        [1] class Person <>g__initLocal0)
    L_0000: newobj instance void Person::.ctor()
    L_0005: stloc.1 
    L_0006: ldloc.1 
    L_0007: ldstr "Philippe"
    L_000c: callvirt instance void Person::set_Name(string)
    L_0011: ldloc.1 
    L_0012: ldstr "phil@phil.com"
    L_0017: callvirt instance void Person::set_Mail(string)
    L_001c: ldloc.1 
    L_001d: stloc.0 
    L_001e: ldloc.0 
    L_001f: callvirt instance string [mscorlib]System.Object::ToString()
    L_0024: pop 
    L_0025: ret 
}

The second gives this:

.method private hidebysig instance void SetProperties() cil managed
{
    .maxstack 2
    .locals init (
        [0] class Person person)
    L_0000: newobj instance void Person::.ctor()
    L_0005: stloc.0 
    L_0006: ldloc.0 
    L_0007: ldstr "Philippe"
    L_000c: callvirt instance void Person::set_Name(string)
    L_0011: ldloc.0 
    L_0012: ldstr "phil@phil.com"
    L_0017: callvirt instance void Person::set_Mail(string)
    L_001c: ldloc.0 
    L_001d: callvirt instance string [mscorlib]System.Object::ToString()
    L_0022: pop 
    L_0023: ret 
}

As you can see, nearly identical code is generated. See below for the exact C# code I compiled.

Performance measurements show very similar results with a very small performance improvement for using the object initializer syntax:

Method               Iterations per second
ObjectInitializer    8.8 million
SetProperties        8.6 million

Code I used for testing the performance:

using System;

class Person
{
    public string Name { get; set; }
    public string Mail { get; set; }
}

class Program
{
    private void ObjectInitializer()
    {
        Person person = new Person()
        {
            Name = "Philippe",
            Mail = "phil@phil.com",
        };
        person.ToString();
    }

    private void SetProperties()
    {
        Person person = new Person();
        person.Name = "Philippe";
        person.Mail = "phil@phil.com";
        person.ToString();
    }

    private const int repetitions = 100000000;

    private void Time(Action action)
    {
        DateTime start = DateTime.UtcNow;
        for (int i = 0; i < repetitions; ++i)
        {
            action();
        }
        DateTime end = DateTime.UtcNow;
        Console.WriteLine(repetitions / (end - start).TotalSeconds);
    }

    private void Run()
    {
        Time(ObjectInitializer);
        Time(SetProperties);
        Console.WriteLine("Finished");
        Console.ReadLine();
    }

    private static void Main()
    {
        new Program().Run();
    }
}
查看更多
ゆ 、 Hurt°
3楼-- · 2019-02-05 12:40

One additional thing worth noting is this:

If you fail to handle an exception in your constructor, you'll get a TypeInitializationException. While that may not seem so bad, the truth is that it conceals the real cause of the problem, and makes it harder to track down.

If, on the other hand, you use an object initializer, you're invoking each property individually outside of the constructor, and any thrown exceptions will be very clear and very evident: they won't be masked by the TypeInitializationException.

In general, it's a bad idea to throw exceptions in a constructor. If you want to avoid that scenario, go with the initializer.

查看更多
淡お忘
4楼-- · 2019-02-05 12:49

Performance-wise there is no significant difference, as other replies have shown.

However, creating an object using an initializer with 2 parameters seems to me like you state your intent to anyone who is using it, forming a "contract" saying: "these 2 parameters are the minimum for the functionality of the class" (although the correct way to express that intent would be to use a constructor).

I tend to think of the initializer syntax this way, although it's more or less just syntactic sugar. I use a mix of both syntaxes in my code. But then again, that's my personal style.

查看更多
太酷不给撩
5楼-- · 2019-02-05 12:57

As others have said, no, there is no difference. Note that the first example isn't actually using a constructor for those arguments. It's using the "object initializer" language feature introduced in C# 3.0. The constructor being called is the default parameterless constructor just like the second example.

The two examples actually compile down to the same IL code and do exactly the same thing. The first example is just syntactic sugar to accomplish the task <opinion>in an easier and more expressive way</opinion>.

查看更多
走好不送
6楼-- · 2019-02-05 12:57

No. The first way is new in .NET 3.5 but the second example is for previous versions of C#.

查看更多
登录 后发表回答