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

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

8 ответов

Решение

Инициализаторы объектов были добавлены в 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 для этого класса.

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

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

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

Когда вы делаете

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;

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

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

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

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

Марк

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


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

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

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

    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() {}

Теперь, годы спустя, я пересматриваю использование конструкторов вместо инициализаторов объектов. Мне всегда нравились инициализаторы объектов, так как они быстрые и простые. Выберите, какие поля вы хотите установить, установите их, и все готово.

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

Но еще лучшим решением является использование ключевого слова «required» в полях, которые должны быть заполнены при создании, будь то с помощью конструктора или инициализатора объекта. Это новое ключевое слово C# 11, которое поставляется с .net 7.

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

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

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

Другие вопросы по тегам