В чем разница между инициализатором объекта и конструктором?

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


person Pete    schedule 11.04.2009    source источник


Ответы (7)


Инициализаторы объектов были добавлены в C # 3, чтобы упростить создание объектов, когда вы используете объект.

Конструкторы выполняются с заданными 0 или более параметрами и используются для создания и инициализации объекта до, когда вызывающий метод получит дескриптор созданного объекта. Например:

MyObject myObjectInstance = new MyObject(param1, param2);

В этом случае конструктор MyObject будет запущен со значениями param1 и param2. Оба они используются для создания нового MyObject в памяти. Созданный объект (который настроен с использованием этих параметров) возвращается и устанавливается в myObjectInstance.

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

Однако часто есть «лишние» свойства, которые могут быть установлены, но не обязательны. С этим можно справиться с помощью перегруженных конструкторов, но это приводит к появлению большого количества конструкторов, которые не обязательно полезны в большинстве случаев.

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

MyObject myObjectInstance = new MyObject(param1, param2)
{
    MyProperty = someUsefulValue
};

Это будет вести себя примерно так же, как если бы вы это сделали:

MyObject myObjectInstance = new MyObject(param1, param2);
myObjectInstance.MyProperty = someUsefulValue;

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

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

person Reed Copsey    schedule 11.04.2009
comment
Я согласен, но хотел бы добавить, что инициализатор объекта отладки может быть болезненным, особенно если у вас есть вложенная структура, поскольку инициализатор объекта считается одной строкой кода (хорошо отформатирован), как и мое предложение. - person CrnaStena; 28.03.2013
comment
@ Reed-Copsey очень хорошее объяснение, будет ли прирост производительности с инициализаторами объектов или это только для удобства чтения? - person Mahender; 17.01.2014
comment
@Mahender На самом деле, при использовании инициализаторов объектов обычно возникают (очень, очень маленькие) потери производительности. Можно написать конструкторы, чтобы они были более эффективными. - person Reed Copsey; 17.01.2014
comment
Ваш ответ хорош, но ваш пример неверен. Пожалуйста, обновите свой код на основе ответа @nawfal. У вашего ответа так много голосов, что никто не посмотрит на другого, и это заставит многих людей неправильно понять, как работает инициализатор объекта. - person George Vovos; 13.11.2015
comment
Я не понимаю, как вам нужно определять множество перегруженных конструкторов для обработки необязательных свойств. Необязательные параметры в конструкторе должны быть в порядке, это не java. - person bgusach; 30.11.2015
comment
Вам придется взвесить читабельность кода и его правильность. Параметры в конструкторах заставляют вас устанавливать все переменные. Если вы забудете установить одну переменную, компилятор пожалуется. Если вы забудете переменную при использовании списка инициализаторов, вы не заметите ее до времени выполнения (а может быть, даже не сразу). Более того: поле не может быть доступно только для чтения, что делает возможными случайные изменения без жалоб компилятора. - person Harald Coppoolse; 19.01.2017
comment
@bgusach Хотя в конструкторе можно использовать необязательные параметры, правило анализа кода CA1026: Не следует использовать параметры по умолчанию предупреждает, что это не считается хорошей практикой. (То есть для общедоступного или защищенного конструктора или метода. Анализ кода не вызывает это предупреждение для закрытого конструктора или метода.) - person DavidRR; 17.01.2018

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

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

Вы могли бы использовать конструктор без помощи инициализатора объекта, если конструктор в достаточной степени задает начальное состояние объекта. Однако инициализатор объекта должен использоваться вместе с конструктором. Синтаксис требует явного или неявного использования (VB.Net и C #) конструктора для создания начального объекта. Вы могли бы использовать инициализатор объекта, когда конструктор недостаточно инициализирует объект для вашего использования, и несколько простых наборов полей и / или свойств будут.

person JaredPar    schedule 11.04.2009
comment
Было бы хорошо добавить, что это конструктор по умолчанию, который вызывается при вызове инициализатора объекта, просто для ясности - person Abraham Philip; 06.07.2018
comment
Я только что исправил неприятную проблему с нулевой ссылкой, потому что кто-то подумал, что это не после. - person Daniel Sharp; 18.07.2018

Когда ты делаешь

Person p = new Person { Name = "a", Age = 23 };

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

Person tmp = new Person(); //creates temp object calling default constructor
tmp.Name = "a";
tmp.Age = 23;
p = tmp;

Теперь это облегчает поведение, подобное this. Важно знать, как работают инициализаторы объектов.

person nawfal    schedule 31.05.2013
comment
может это быть просто человек p = новый человек {Name = a}? - person h-rai; 07.08.2014
comment
@ nick-s да, очень понравилось. Для этого нужен инициализатор объекта. Вы инициализируете участников, которых хотите. - person nawfal; 07.08.2014
comment
Я не знал, что конструктор можно пропустить. Спасибо. - person anar khalilov; 12.06.2015
comment
@AnarKhalilov и не только это, я считаю, что без скобок он намного элегантнее. Возможно, это немного хуже передает суть [круглые скобки говорят о том, что конструктор был вызван]. - person nawfal; 12.06.2015

Если у вас есть свойства, которые ДОЛЖНЫ быть установлены для вашего объекта, чтобы он работал должным образом, один из способов - предоставить только один конструктор, который требует этих обязательных свойств в качестве параметров.

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

Инициализаторы объектов - это просто «удобство синтаксиса» для сокращения начальных назначений. Красиво, но не очень функционально.

Марк

person marc_s    schedule 11.04.2009
comment
Другой способ гарантировать, что существенные свойства установлены для объекта во время создания, - это предоставить статический (фабричный) метод для класса, который возвращает сконструированный объект. Этот фабричный метод создает объект с помощью конструктора private. (Может быть полезно определение нескольких частных конструкторов.) - person DavidRR; 17.01.2018
comment
... Кроме того, иногда бывает полезно создать статическую фабрику class, которая отвечает за создание экземпляров одного или нескольких других классов. Например, см. File.Create Method (String) (и его перегрузки), который создает объект FileStream. - person DavidRR; 17.01.2018

Конструктор - это метод (возможно), принимающий параметры и возвращающий новый экземпляр класса. Он может содержать логику инициализации. Ниже вы можете увидеть пример конструктора.


public class Foo
{
    private SomeClass s;
    public Foo(string s)
    {
       s = new SomeClass(s);
    }
}

Теперь рассмотрим следующий пример:


public class Foo
{
    public SomeClass s { get; set; }
    public Foo() {}
}

Вы можете достичь того же результата, что и в первом примере, используя инициализатор объекта, предполагая, что вы можете получить доступ к SomeClass, с помощью следующего кода:


new Foo() { s = new SomeClass(someString) }

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

person em70    schedule 11.04.2009

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

var orderLineReceiver = new { ReceiverName = "Name Surname", ReceiverAddress = "Some address" };

Подробнее об этом - Инициализаторы объектов и коллекций

person Sharunas Bielskis    schedule 10.10.2019

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

    class Program
    {
        static void Main(string[] args)
        {
            List<OrderLine> ordersLines = new List<OrderLine>()
            {
                new OrderLine {Platform = "AmazonUK", OrderId = "200-2255555-3000012", ItemTitle = "Test product 1"},
                new OrderLine {Platform = "AmazonUK", OrderId = "200-2255555-3000013", ItemTitle = "Test product 2"},
                new OrderLine {Platform  = "AmazonUK", OrderId = "200-2255555-3000013", ItemTitle = "Test product 3"}
            };
        }
    }
    class OrderLine
    {
        public string Platform { get; set; }
        public string OrderId { get; set; }
        public string ItemTitle { get; set; }
    }

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

public OrderLine(string platform, string orderId, string itemTitle)
{
   Platform = platform;
   OrderId = orderId;
   ItemTitle = itemTitle;
}

Компилятор покажет ошибку - не указан аргумент, соответствующий требуемому формальному параметру…. Это можно исправить, включив в класс OrderLine явный конструктор по умолчанию без параметров:

public OrderLine() {}
person Sharunas Bielskis    schedule 10.10.2019