Установка свойств с помощью инициализации объекта или нет: какая разница? - PullRequest
34 голосов
/ 11 февраля 2011

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

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

и этим

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

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

Ответы [ 5 ]

43 голосов
/ 11 февраля 2011

Они почти полностью эквивалентны, за исключением того, что первый метод (с использованием инициализатора объекта ) работает только в 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 "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 
}

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

.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 
}

Как видите, генерируется практически идентичный код.Ниже приведен точный код 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 = "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();
    }
}
9 голосов
/ 12 февраля 2011

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

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

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

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

2 голосов
/ 11 февраля 2011

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

Два примера на самом деле компилируются в один и тот же код IL и делают точно то же самое. Первый пример - просто синтаксический сахар для более простого и выразительного выполнения задачи .

0 голосов
/ 09 августа 2015

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

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

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

0 голосов
/ 11 февраля 2011

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

...