это плохо для использования блока инициализатора

Привет я использую блок инициализатора в C#

new Something { foo = 1, bar = 2 };

но люди говорят, что это - плохая практика.

Я не думаю, что это неправильно, не так ли?

11
задан Brian Rasmussen 4 April 2010 в 14:54
поделиться

7 ответов

Блоки инициализатора - ВЕЛИКОЛЕПНАЯ практика по следующим причинам:

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

     this. ObjA = new ObjA 
     {
    Age = 20, 
    Name = "123", 
    }; 
     
     // это .ObjA не будет установлен до тех пор, пока все свойства не будут определены 
     // - безопаснее при многопоточности 
     
  2. Конструктор без параметров все еще может делать что-то за сценой (например, инициализировать члены состояния).

  3. Вы можете использовать вместе с конструкторами с параметрами

     this.ObjA = new ObjA (20) 
     {
    Name = "123", 
    }; {{ 1}} 
  4. Использование конструкторов без параметров лучше для (де) сериализации сценариев

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

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

3
ответ дан 3 December 2019 в 04:13
поделиться

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

С другой стороны, инициализаторы объектов, безусловно, полезны в тех случаях, когда разумно иметь изменяемые типы. Например, ProcessStartInfo эффективно используется в качестве типа построителя для Process . Полезно иметь возможность написать:

var info = new ProcessStartInfo { 
    FileName = "notepad.exe",
    Arguments = "foo.txt",
    ErrorDialog = true
};
Process process = Process.Start(info);

В самом деле, вы даже можете сделать все это встроенным, вместо того, чтобы иметь дополнительную переменную. Порт My Protocol Buffers использует такой же шаблон:

Foo foo = new Foo.Builder { 
    FirstProperty = "first",
    SecondProperty = "second"
}.Build();

Теперь одной альтернативой шаблону построителя являются параметры конструктора (возможно, через фабричные методы).Историческим недостатком этого является то, что вам нужны были разные перегрузки в зависимости от того, какие свойства были установлены, и если несколько параметров имели один и тот же тип, было бы трудно определить, какие из них были. C # 4 значительно упрощает эту задачу, используя необязательные параметры и именованные аргументы. Например, если вы создаете класс электронной почты, вы можете иметь:

Email email = new Email(
    from: "skeet@pobox.com",
    to: "jon@example.com",
    subject: "Test email",
    body: textVariable
);

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

9
ответ дан 3 December 2019 в 04:13
поделиться

, но люди считают это плохой практикой.

Кто это сказал? По крайней мере, это спорное заявление.

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

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

var x = new Something { Foo = 1, Bar = 2 };

с

var x = new Something(1, 2);

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

var x = new Something();
x.Foo = 1;
x.Bar = 2;

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

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

4
ответ дан 3 December 2019 в 04:13
поделиться

Думаю, это хорошо.

Потому что это сокращает объем набора текста

0
ответ дан 3 December 2019 в 04:13
поделиться

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

Пользователь вашего класса будет знать, что он не может создать объект, не указав эти значения.

1
ответ дан 3 December 2019 в 04:13
поделиться

Сомнительная (не скажу «плохая») практика использования блоков инициализации вместо соответствующей перегрузки конструктора , если он существует.

public class Entity
{
    public Entity()
    {
    }

    public Entity(int id, string name)
    {
        this.ID = id;
        this.Name = name;
    }

    public int ID { get; set; }
    public string Name { get; set; }
}

Если у вас есть этот очень простой класс, то, как правило, предпочтительнее писать:

var entity = new Entity(1, "Fred");

... чем писать:

var entity = new Entity { ID = 1, Name = "Fred" };

Для этого есть как минимум две веские причины:

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

  2. Ваш код не сломается, если одно или несколько из этих свойств будут изменены или станут доступны только для чтения (что, вероятно, должно было быть в ID , но, возможно, не было. из-за архитектурных ограничений, таких как ORM).

Однако есть один случай, когда у вас есть для использования инициализаторов вместо перегруженных конструкторов, и это когда цепочка выборок в запросе Linq to SQL / EF:

var bars =
    from f in ctx.Foo
    select new Bar { X = f.X, Y = f.Y };
var bazzes =
    from b in bars
    select new Baz { ... };

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

В других случаях вам следует предпочесть перегрузку конструктора инициализатору.

Если нет полезной / релевантной перегрузки конструктора , которая может делать то же самое, что и ваш инициализатор, то продолжайте и напишите инициализатор, в этом нет ничего плохого. Эта функция существует по уважительной причине - она ​​упрощает запись кода и чтение.

8
ответ дан 3 December 2019 в 04:13
поделиться

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

Блоки инициализатора очень удобны для некоторых новых функций C # 3.0, но вы должны помнить, что они не предназначены для замены параметров в конструкторе.

0
ответ дан 3 December 2019 в 04:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: