2010-04-04 2 views

ответ

4

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

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

Кажется, что на данный момент все в ярости, и многие известные блоги 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; 

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

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

+0

C# 4 позволяет вызовам конструктора выглядеть как инициализаторы объектов - см. Мое сообщение для примера. –

+0

@ Jon Приятно, что C# 4, наконец, вводит это. Интересно, что такая же особенность в VB очень редко используется, хотя VB.NET имела это с самого начала ... Интересно, почему. –

+0

@ Konrad: Вы можете получить свое имя, если хотите. :) http://meta.stackexchange.com/questions/45208/possible-feature-request-revert-a-display-name-change-within24-hours – missingfaktor

0

Я думаю, что это хорошо.

Потому что это уменьшает ваш набрав намного

+1

На самом деле использование соответствующего перегруженного конструктора будет * меньше * печатать. Однако использование инициализаторов явно более читаемо *, чем использование конструктора. –

+4

Ввод текста почти * никогда * ограничивающий фактор в программировании. Код для удобочитаемости, а не сокращение набора. –

1

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

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

3

Initializer блоки GREAT практика по следующим причинам:

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

    this.ObjA = new ObjA 
    { 
        Age = 20, 
        Name = "123", 
    }; 
    
    // this.ObjA will not be set until properties have all been defined 
    // - safer when multithreading 
    
  2. параметрирования менее конструктор может еще делать вещи за сценой (например, инициализировать элементы состояния).

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

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

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

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

+1

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

+1

Объекты с неизменяемыми состояниями не имеют устанавливаемых свойств, поэтому блоки инициализации для них не являются опцией. –

8

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

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, но, возможно, не было связано с архитектурными ограничениями как у ОРМ).

Однако есть один случай, когда вы имеют использовать инициализаторы вместо перегруженных конструкторов, и это, когда сцепление выбирает в Linq к 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 { ... }; 

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

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

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

+0

Это так много? Я не помню, как в прошлый раз я видел сложный/дорогой конструктор или имел существенное изменение основного свойства (таким образом, мой редактор не мог тривиально исправить).Я все время читаю код с объектными конструкторами и хочу знать, что означают их параметры. – Ken

+0

@Ken: клиенты WCF ('ClientBase ') - один из примеров дорогостоящих объектов. Многие классы, которые я пишу, будут выполнять задачи инициализации по умолчанию в конструкторе по умолчанию. Хотя я не согласен с вами в отношении удобочитаемости, важно также понимать, что инициализаторы являются просто синтаксическим сахаром для определителей свойств (например, 'var x = new MyClass(); x.ID = 1; x.Name =" Fred ";'), который просто не имеет той же семантики, что и предоставление этих значений конструктору. – Aaronaught

0

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

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

9

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

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

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

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

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

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

Email email = new Email(
    from: "[email protected]", 
    to: "[email protected]", 
    subject: "Test email", 
    body: textVariable 
); 

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

+2

Интересно в стороне; синтаксис синтаксиса SO считает, что «from» - это ключевое слово (предположительно, из поддержки выделения LINQ.) –

+0

Итак, именованные параметры выглядят очень хорошей альтернативой тому, что я иногда писал: «Fool x = new Fool (« John «/ * First * /,« Doe »/ * Last * /, 79/* Age * /);' и они могут помочь дифференцировать неоднозначные вызовы методов, когда один из параметров имеет значение NULL, но есть также случай использования имени аргументы контрпродуктивны? –

+0

@HamishGrubijan: Ну, я бы не использовал их, когда смысл уже очевиден ... и это делает ваш код чувствительным к переименованию параметров. Это всегда было переломным для переименования параметров (из-за других языков), но названные аргументы открываются более широко. –

Смежные вопросы