Установка свойств через инициализацию объекта или нет: есть ли разница?

Вот простой вопрос: есть ли разница (в производительности) между этим:

Person person = new Person()
{
  Name = "Philippe",
  Mail = "[email protected]",
};

и это

Person person = new Person();
person.Name = "Philippe";
person.Mail = "[email protected]";

Вы можете представить себе более крупный объект с большим количеством свойств.


person Philippe Lavoie    schedule 11.02.2011    source источник
comment
Также стоит проверить этот ответ на аналогичный вопрос.   -  person Mike Guthrie    schedule 21.08.2013


Ответы (5)


Они почти полностью эквивалентны, за исключением того, что первый метод (с использованием инициализатора объекта ) работает только в C# 3.0 и новее. Любая разница в производительности незначительна и не стоит о ней беспокоиться.

Они производят почти идентичный код IL. Первый дает это:

.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 "[email protected]"
    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 
}

Второй дает это:

.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 "[email protected]"
    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 
}

Как видите, генерируется почти идентичный код. Ниже приведен точный код C#, который я скомпилировал.

Измерения производительности показывают очень похожие результаты с очень небольшим улучшением производительности при использовании синтаксиса инициализатора объекта:

Method               Iterations per second
ObjectInitializer    8.8 million
SetProperties        8.6 million

Код, который я использовал для тестирования производительности:

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 = "[email protected]",
        };
        person.ToString();
    }

    private void SetProperties()
    {
        Person person = new Person();
        person.Name = "Philippe";
        person.Mail = "[email protected]";
        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();
    }
}
person Mark Byers    schedule 11.02.2011
comment
Ну, пока у вас есть компилятор 3.0, вы можете использовать его в коде, написанном для .net 2.0. - person ; 11.02.2011
comment
Так что это сложнее сделать с помощью инициализатора объекта. Есть ли предпочтительный способ? - person Philippe Lavoie; 11.02.2011
comment
Личное мнение: для простых объектов или инициализированных только статическими значениями, как в этом примере, блок инициализатора подходит - чистый для чтения. Если мне нужно назначить много свойств или использовать переменные, я обычно использую стандартную опцию назначения. Просто потому, что если он по какой-либо причине (нулевой объект и т. д.) внутри блока OI дает сбой, становится сложнее понять, где он терпит неудачу. Где со стандартным назначением он скажет вам, где именно проблема. - person Patrick; 23.05.2012

Стоит отметить еще одну вещь:

Если вам не удастся обработать исключение в конструкторе, вы получите исключение TypeInitializationException. Хотя это может показаться не таким уж плохим, правда в том, что это скрывает реальную причину проблемы и затрудняет ее отслеживание.

Если, с другой стороны, вы используете объект initializer, вы вызываете каждое свойство по отдельности вне конструктора, и любые возникающие исключения будут очень четкими и очевидными. : они не будут маскироваться исключением TypeInitializationException.

В общем, генерировать исключения в конструкторе — плохая идея. Если вы хотите избежать этого сценария, используйте инициализатор.

person Mike Hofer    schedule 11.02.2011
comment
+1 за то, что заставил меня понять, что инициализация объекта происходит только ПОСЛЕ запуска конструктора. - person Riegardt Steyn; 17.10.2013

Как говорили другие, нет, нет никакой разницы. Обратите внимание, что в первом примере фактически не используется конструктор для этих аргументов. Он использует языковую функцию «инициализатора объекта», представленную в C# 3.0. Вызываемый конструктор является конструктором без параметров по умолчанию, как и во втором примере.

Два примера фактически компилируются в один и тот же код IL и делают точно одно и то же. Первый пример — это просто синтаксический сахар для выполнения задачи ‹мнение› более простым и выразительным способом‹/мнение›.

person David    schedule 11.02.2011

Нет. Первый способ является новым в .NET 3.5, а второй пример — для предыдущих версий C#.

person Mohammad M. Ramezanpour    schedule 11.02.2011

Как показали другие ответы, с точки зрения производительности существенной разницы нет.

Однако создание объекта с использованием инициализатора с двумя параметрами мне кажется так, будто вы заявляете о своих намерениях всем, кто его использует, формируя «контракт», говоря: «эти 2 параметра являются минимумом для функциональности класса" (хотя правильным способом выразить это намерение было бы использование конструктора).

Я склонен думать о синтаксисе инициализатора таким образом, хотя это более или менее просто синтаксический сахар. Я использую сочетание обоих синтаксисов в своем коде. Но опять же, это мой личный стиль.

person Theodore Zographos    schedule 09.08.2015