Подтвердить что ты не робот

С#: присваивать данные свойствам через конструктор против создания экземпляра

Предположим, что у меня есть класс Album:

public class Album 
{
    public string Name {get; set;}
    public string Artist {get; set;}
    public int Year {get; set;}

    public Album()
    { }

    public Album(string name, string artist, int year)
    {
        this.Name = name;
        this.Artist = artist;
        this.Year = year;
    }
}

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

Через конструктор

var albumData = new Album("Albumius", "Artistus", 2013);

или при создании экземпляра

var albumData = new Album 
                    {
                         Name = "Albumius",
                         Artist = "Artistus",
                         Year = 2013
                    };
4b9b3361

Ответ 1

Оба подхода вызывают конструктор, они просто называют разные. Этот код:

var albumData = new Album 
                {
                     Name = "Albumius",
                     Artist = "Artistus",
                     Year = 2013
                };

является синтаксическим сокращением для этого эквивалентного кода:

var albumData = new Album();
albumData.Name = "Albumius";
albumData.Artist = "Artistus";
albumData.Year = 2013;

Эти два идентичны после компиляции. Поэтому, если конструктор без параметров не был общедоступным:

public Album() { }

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

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

private Album() { }
public Album(string name)
{
    this.Name = name;
}

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

var albumData = new Album("Albumius")
                {
                     Artist = "Artistus",
                     Year = 2013
                };

Результат после компиляции тогда будет идентичен:

var albumData = new Album("Albumius");
albumData.Artist = "Artistus";
albumData.Year = 2013;

Ответ 2

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

public class Album 
{
    // Note that we make the setter 'private'
    public string Name { get; private set; }
    public string Artist { get; private set; }
    public int Year { get; private set; }

    public Album(string name, string artist, int year)
    {
        this.Name = name;
        this.Artist = artist;
        this.Year = year;
    }
}

Если класс определен таким образом, это означает, что на самом деле нет простого способа изменить содержимое класса после его создания. У неизменности есть преимущества. Когда что-то неизменное, намного проще определить, что оно правильно. В конце концов, если он не может быть изменен после построения, тогда нет никакого способа, чтобы он когда-либо был "неправильным" (после того, как вы определили правильность его структуры). Когда вы создаете анонимные классы, например:

new { 
    Name = "Some Name",
    Artist = "Some Artist",
    Year = 1994
};

компилятор автоматически создаст неизменяемый класс (т.е. анонимные классы не могут быть изменены после построения), потому что неизменяемость является настолько полезной. Большинство руководств по стилю С++/Java часто поощряют создание членов const (С++) или final (Java) именно по этой причине. Большие приложения намного проще проверять, когда количество движущихся частей меньше.

Что все сказано, бывают ситуации, когда вы хотите быстро изменить структуру своего класса. Скажем, у меня есть инструмент, который я хочу настроить:

public void Configure(ConfigurationSetup setup);

и у меня есть класс, который имеет несколько элементов, таких как:

class ConfigurationSetup {
    public String Name { get; set; }
    public String Location { get; set; }
    public Int32 Size { get; set; }
    public DateTime Time { get; set; }

    // ... and some other configuration stuff... 
}

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

ConfigurationSetup setup = new ConfigurationSetup {
    Name = "Some Name",
    Location = "San Jose"
};

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

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

Ответ 3

Второй подход инициализатор объекта в С#

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

Первый подход

var albumData = new Album("Albumius", "Artistus", 2013);

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

 var albumData = new Album
        {
            Name = "Albumius",
        };

Инициализатор объектов переводится во что-то вроде:

var albumData; 
var temp = new Album();
temp.Name = "Albumius";
temp.Artist = "Artistus";
temp.Year = 2013;
albumData = temp;

Почему он использует временный объект (в режиме отладки), отвечает на здесь от Jon Skeet.

Что касается преимуществ обоих подходов, то ИМО, инициализатор объектов будет проще использовать специально, если вы не хотите инициализировать все поля. Что касается разницы в производительности, я не думаю, что это произойдет, поскольку инициализатор объекта вызывает конструктор с меньшим значением, а затем назначает свойства. Даже если будет разница в производительности, она должна быть незначительной.