Производительность инициализатора объекта - PullRequest
16 голосов
/ 02 октября 2009

Является ли инициализатор объекта в c # 3.0 быстрее обычного?

Это быстрее

Object object = new Object
{
    id = 1;
}

чем это?

Object object = new Object()

object.id = 1;

Ответы [ 7 ]

22 голосов
/ 02 октября 2009

В режиме Release они будут компилироваться в точный тот же код IL (при условии, что вы на самом деле используете тип со свойством id вместо Object)

Следовательно, по определению не будет разницы в производительности.

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

Однако, синтаксис инициализатора объекта пишется быстрее (меньше набирает), поэтому вы, вероятно, должны его использовать.

9 голосов
/ 02 октября 2009

Хорошо, из комментария [SLaks] [2] и проверки себя после прочтения, оказывается, что разница, которую я здесь описываю, присутствует только в режиме отладки. Если вы компилируете для релиза, они все компилируются в один и тот же код. Узнай что-то новое каждый день :)


(остальная часть ответа предполагает режим отладки.)

Там - это разница в произведенном IL, в отличие от того, что ответили здесь другие, но разница незначительна и фактически не должна оказывать никакого влияния на производительность вашей программы.

Разница в том, что используется инициализатор объекта, например:

Object object = new Object
{
    id = 1;
}

Код фактически скомпилирован, как если бы вы написали это:

Object temp = new Object();
temp.id = 1;
Object object = temp;

(конечно, если не учитывать тот факт, что Object не имеет поля / свойства Id, и вы не можете фактически назвать переменную "object" без использования синтаксиса дословного идентификатора "@object".)

Почему это имеет значение? Ну, одно отличие, которое вы могли бы заметить, заключается в том, что если какое-либо из назначений выдает исключение (либо записывает значение в объект, либо получает значение из выражения или функции, выдает исключение), то с инициализатором объекта вы выиграете ' На самом деле, он не видит какой-либо объект в переменной, тогда как в вашем «ручном» коде этот объект будет там, инициализирован вплоть до точки, где произошло исключение.

Небольшая разница, которая не должна сильно отличаться от производительности , но может изменить поведение вашей программы.

Это можно проверить, посмотрев на IL. Возьми эту программу на C #:

using System;

namespace ConsoleApplication3
{
    class Test
    {
        public Int32 Id { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            M1();
            M2();
        }

        static void M1()
        {
            Test t = new Test();
            t.Id = 1;
        }

        static void M2()
        {
            Test t = new Test { Id = 1 };
        }

        static void M3()
        {
            Test t;
            Test temp = new Test();
            temp.Id = 1;
            t = temp;
        }
    }
}

и скомпилируйте его, пропустите через Reflector , и вы получите это для M1, M2 и M3:

.method private hidebysig static void M1() cil managed
{
    .maxstack 2
    .locals init (
        [0] class ConsoleApplication3.Test t)
    L_0000: nop 
    L_0001: newobj instance void ConsoleApplication3.Test::.ctor()
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: ldc.i4.1 
    L_0009: callvirt instance void ConsoleApplication3.Test::set_Id(int32)
    L_000e: nop 
    L_000f: ret 
}

.method private hidebysig static void M2() cil managed
{
    .maxstack 2
    .locals init (
        [0] class ConsoleApplication3.Test t,
        [1] class ConsoleApplication3.Test <>g__initLocal0)
    L_0000: nop 
    L_0001: newobj instance void ConsoleApplication3.Test::.ctor()
    L_0006: stloc.1 
    L_0007: ldloc.1 
    L_0008: ldc.i4.1 
    L_0009: callvirt instance void ConsoleApplication3.Test::set_Id(int32)
    L_000e: nop 
    L_000f: ldloc.1 
    L_0010: stloc.0 
    L_0011: ret 
}

 .method private hidebysig static void M3() cil managed
{
    .maxstack 2
    .locals init (
        [0] class ConsoleApplication3.Test t,
        [1] class ConsoleApplication3.Test temp)
    L_0000: nop 
    L_0001: newobj instance void ConsoleApplication3.Test::.ctor()
    L_0006: stloc.1 
    L_0007: ldloc.1 
    L_0008: ldc.i4.1 
    L_0009: callvirt instance void ConsoleApplication3.Test::set_Id(int32)
    L_000e: nop 
    L_000f: ldloc.1 
    L_0010: stloc.0 
    L_0011: ret 
}

Если вы посмотрите на код, единственное, что отличается между M2 и M3, это имя второго локального (<>g__initLocal0 против temp).

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

2 голосов
/ 02 октября 2009

AFAIK это просто синтаксический сахар - произведенный IL будет таким же

1 голос
/ 02 октября 2009

Я не тестировал его, но я бы удивился, если бы они не скомпилировали одно и то же.

Тем не менее, мне легче печатать, когда мне нужно что-то вроде

var bob = service.GetSingle( new Constraint { UserName = "Bob" } );

Мне очень не нравятся повторные присвоения свойств, таких как

var c = new Constraint();
c.UserName = "Bob";
c.Position = Positions.Manager;
var bob = service.GetSingle( c );
1 голос
/ 02 октября 2009

Если есть какие-либо различия в производительности (которые, я сомневаюсь, есть), они незначительны. Оптимизируйте только там, где профилировщик сказал вам сделать это.

1 голос
/ 02 октября 2009

Может быть быстрее набирать текст, но он компилируется в тот же код, поэтому преимущества времени выполнения нет.

1 голос
/ 02 октября 2009

Нет, это одно и то же.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...