.NET создание объектов, что быстрее? - PullRequest
3 голосов
/ 15 сентября 2010

Есть ли разница между этими двумя способами создания объекта?

new MyClass() { Id = 1, Code = "Test" };

или

MyClass c = new MyClass();
c.Id = 1;
c.Code = "Test";

Что быстрее? Я предполагаю, что нет никакой разницы между 2.

Ответы [ 4 ]

18 голосов
/ 15 сентября 2010

Второе, вероятно, будет почти наверняка незначительно быстрее, потому что логически здесь задействовано меньшее количество заданий.В первом случае код фактически эквивалентен:

MyClass tmp = new MyClass()
tmp.Id = 1;
tmp.Code = "Test";
MyClass c = tmp;

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

РЕДАКТИРОВАТЬ: я только что попытался скомпилировать с включенной оптимизацией и без нее, и в этом случае "новой переменной" компилятор C #исключает два , если оптимизирует.Это не иначе (но JIT все еще мог).В случае «переназначения» это может иметь заметное значение, поэтому я не ожидаю такой же оптимизации.Хотя я не проверял.

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

РЕДАКТИРОВАТЬ: Я думал, что люди могут быть заинтересованы в тесте, показывающий, что это имеет значение.Это намеренно ужасный код, который замедляет скрытое дополнительное присваивание - я создал большую изменчивую структуру.Urgh.В любом случае ...

using System;
using System.Diagnostics;

struct BigStruct
{
    public int value;
    #pragma warning disable 0169
    decimal a1, a2, a3, a4, a5, a6, a7, a8;
    decimal b1, b2, b3, b4, b5, b6, b7, b8;
    decimal c1, c2, c3, c4, c5, c6, c7, c8;
    decimal d1, d2, d3, d4, d5, d6, d7, d8;
    #pragma warning restore 0169
}

class Test
{
    const int Iterations = 10000000;

    static void Main()
    {
        Time(NewVariableObjectInitializer);
        Time(ExistingVariableObjectInitializer);
        Time(NewVariableDirectSetting);
        Time(ExistingVariableDirectSetting);
    }

    static void Time(Func<int> action)
    {
        Stopwatch stopwatch = Stopwatch.StartNew();
        action();
        stopwatch.Stop();
        Console.WriteLine("{0}: {1}ms",
                          action.Method.Name,
                          stopwatch.ElapsedMilliseconds);
    }

    static int NewVariableObjectInitializer()
    {
        int total = 0;
        for (int i = 0; i < Iterations; i++)
        {
            BigStruct b = new BigStruct { value = i };
            total += b.value;
        }
        return total;
    }

    static int ExistingVariableObjectInitializer()
    {
        int total = 0;
        BigStruct b;
        for (int i = 0; i < Iterations; i++)
        {
            b = new BigStruct { value = i };
            total += b.value;
        }
        return total;
    }

    static int NewVariableDirectSetting()
    {
        int total = 0;
        for (int i = 0; i < Iterations; i++)
        {
            BigStruct b = new BigStruct();
            b.value = i;
            total += b.value;
        }
        return total;
    }

    static int ExistingVariableDirectSetting()
    {
        int total = 0;
        BigStruct b;
        for (int i = 0; i < Iterations; i++)
        {
            b = new BigStruct();
            b.value = i;
            total += b.value;
        }
        return total;
    }
}

Результаты (с / o + / debug -):

NewVariableObjectInitializer: 3328ms
ExistingVariableObjectInitializer: 3300ms
NewVariableDirectSetting: 1464ms
ExistingVariableDirectSetting: 1491ms

Я несколько удивлен тем, что версия NewVariableObjectInitializer медленнее, чем версии с прямой установкой ..похоже, что компилятор C # не оптимизирует этот случай так, как это делается для ссылочных типов.Я подозреваю, что есть некоторые тонкости вокруг типов значений, которые мешают этому.

4 голосов
/ 15 сентября 2010

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

Создание 100 миллионов объектов заняло около 1,5 секундпоэтому нет особых оснований пытаться сделать это быстрее.

Лично я предпочитаю параметризованный конструктор, так как тогда я могу сделать установщики свойств частными, чтобы я мог сделать класс неизменным, если захочу:

class MyClass {

  public int Id { get; private set; }
  public string Code { get; private set; }

  public MyClass(int id, string code) {
    Id = id;
    Code = code;
  }

}

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

3 голосов
/ 15 сентября 2010

Чтобы проиллюстрировать код M Skeet, вот IL (обратите внимание на дополнительный ldloc stloc для метода # 1)

  IL_0001:  newobj     instance void ConsoleApplication1.Program/MyClass::.ctor()
  IL_0006:  stloc.2
  IL_0007:  ldloc.2
  IL_0008:  ldc.i4.1
  IL_0009:  callvirt   instance void ConsoleApplication1.Program/MyClass::set_Id(int32)
  IL_000e:  nop
  IL_000f:  ldloc.2
  IL_0010:  ldstr      "Test"
  IL_0015:  callvirt   instance void ConsoleApplication1.Program/MyClass::set_Code(string)
  IL_001a:  nop
  IL_001b:  ldloc.2
  IL_001c:  stloc.0


  IL_001d:  newobj     instance void ConsoleApplication1.Program/MyClass::.ctor()
  IL_0022:  stloc.1
  IL_0023:  ldloc.1
  IL_0024:  ldc.i4.1
  IL_0025:  callvirt   instance void ConsoleApplication1.Program/MyClass::set_Id(int32)
  IL_002a:  nop
  IL_002b:  ldloc.1
  IL_002c:  ldstr      "Test"
  IL_0031:  callvirt   instance void ConsoleApplication1.Program/MyClass::set_Code(string)
  IL_0036:  nop
2 голосов
/ 15 сентября 2010

Они одинаковы.Но мы все предпочитаем первый, он более читабелен и понятен, не так ли?

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