2008-11-18 7 views
86

ли это лучше для инициализации переменных-членов класса по декларацииИнициализация переменной элемента C#; лучшая практика?

private List<Thing> _things = new List<Thing>(); 
private int _arb = 99; 

или в конструктор по умолчанию?

private List<Thing> _things; 
private int _arb; 

public TheClass() 
{ 
    _things = new List<Thing>(); 
    _arb = 99; 
} 

Это просто вопрос стиля или есть компромиссы с производительностью, так или иначе?

+2

Возможный дубликат http://stackoverflow.com/questions/24551/best-practice-initialize-class-fields-in-constructor-or-at-declaration – goodeye 2013-03-03 03:10:53

ответ

70

С точки зрения производительности, нет никакой реальной разницы; Инициализаторы полей реализуются как логика конструктора. Единственное различие заключается в том, что инициализаторы поля происходят до любого «базового»/«этого» конструктора.

Конструктора подход может быть использован с автоматическими Реализуемыми свойствами (поле инициализаторы не могу) - т.е.

[DefaultValue("")] 
public string Foo {get;set;} 
public Bar() { // ctor 
    Foo = ""; 
} 

Кроме этого, я, как правило, предпочитает синтаксис поле инициализатора; Я считаю, что держит вещи локализованы - т.е.

private readonly List<SomeClass> items = new List<SomeClass>(); 
public List<SomeClass> Items {get {return items;}} 

Я не должен идти на охоту вверх и вниз, чтобы найти, где он назначен ...

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

public Bar() : this("") {} 
public Bar(string foo) {Foo = foo;} 

редактировать: как побочный комментарий, обратите внимание, что в приведенном выше, если есть другие поля (не показаны) с инициализаторами поля, то они только непосредственно инициализируются в конструкторах, которые вызывают base(...), то есть public Bar(string foo) ctor. Другой конструктор делает не инициализаторы полей, так как он знает, что они сделаны this(...) ctor.

+0

Я знаю, что это старый пост, но у меня есть вопрос: что вы имели в виду под «конструкторами, которые называют base (. ..) "? вы публичный Bar (строка foo) {Foo = foo;}, похоже, не вызывает: base(), или это происходит неявно? Спасибо за вашу помощь. – 2012-09-22 07:49:22

+1

@Bruno для `class`, каждый конструктор имеет неявный`: base() `, если вы не добавите что-то более конкретное, - которое может быть`: base (123, "abc") `или может быть`: this (123 , "abc"). – 2012-09-22 09:51:54

+0

@Marc Итак, инициализация в порядке (1) fieldInitializer (2) BaseConstructor (3) LocalConstructor – prabhakaran 2014-05-28 05:50:26

1

Например, переменные, это в основном вопрос стиля (я предпочитаю использовать конструктор). Для статических переменных существует performance benefit для инициализации встроенного (не всегда возможно, конечно).

0

Это действительно зависит от вас.
Я часто инициализирую их inline, потому что мне не нравится иметь конструктор, когда мне это действительно не нужно (мне нравятся маленькие классы!).

8

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

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

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

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

2

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

Я бы либо инициализировал, где объявлено. Или конструктор (ы) вызывает функцию Init().

3

Одним из основных ограничений с инициализаторами полей является то, что их невозможно вставить в блок try-finally. Если в инициализаторе поля выбрано исключение, любые ресурсы, которые были выделены в предыдущих инициализаторах, будут оставлены; нет способа предотвратить это. Другие ошибки в конструкции могут быть рассмотрены, если неловко, путем использования защищенного базового конструктора с IDisposable по ссылке и указания его на себя в качестве самой первой операции. Затем можно избежать вызова конструктора, кроме как с помощью фабричных методов, которые в случае исключения вызовут Dispose на частично созданном объекте. Эта защита позволит очистить IDisposables, созданные в инициализаторах производного класса, если конструктор основного класса завершит работу после «контрабанды» ссылки на новый объект. К сожалению, нет возможности обеспечить такую ​​защиту, если инициализатор поля не работает.

0

В добавление к вышесказанному - у вас всегда есть конструктор при реализации классов, имеющих реализацию. Если вы не объявите один, тогда инструктор по умолчанию будет выведен компилятором [public Foo() {}]; конструктор, который не принимает аргументов.

Часто я предпочитаю предлагать оба подхода. Разрешить конструкторы для тех, кто хочет их использовать, и разрешить инициализаторы полей для ситуаций, когда вы хотите использовать упрощенную или стандартную реализацию вашего класса/типа. Это добавляет гибкость вашему коду. Имейте в виду, что каждый может использовать инициализатор поля по умолчанию, если они выбирают ... обязательно объявите его вручную, если вы предложите несколько конструкторов - public Foo() {}