Инициализировать поля класса в конструкторе или при объявлении?

Я недавно программировал на C # и Java, и мне любопытно, где лучше всего инициализировать поля моего класса.

Должен ли я сделать это при объявлении?:

public class Dice
{
    private int topFace = 1;
    private Random myRand = new Random();

    public void Roll()
    {
       // ......
    }
}

или в конструкторе?:

public class Dice
{
    private int topFace;
    private Random myRand;

    public Dice()
    {
        topFace = 1;
        myRand = new Random();
    }

    public void Roll()
    {
        // .....
    }
}

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

389
задан 20.09.2019, 02:42

7 ответов

Мои правила:

  1. не инициализируют со значениями по умолчанию в объявлении (null, false, 0, 0.0 †¦).
  2. Предпочитают инициализацию в объявлении, если у Вас нет параметра конструктора, который изменяет значение поля.
  3. , Если значение полевых изменений из-за параметра конструктора поместило инициализацию в конструкторов.
  4. Быть последовательным в Вашей практике (самое важное правило).
291
ответ дан 04.10.2019, 13:36
  • 1
    Я ожидаю, что kokos означает, что Вы не должны инициализировать участников к их значениям по умолчанию (0, ложь, пустой указатель и т.д.), так как компилятор сделает это для Вас (1).. Но если Вы хотите инициализировать поле к чему-нибудь кроме его значения по умолчанию, необходимо сделать это в объявлении (2).. Я думаю, что это могло бы быть использование слова " default" это смущает Вас. – Ricky Helgesson 12.10.2012, 07:12
  • 2
    Я не соглашаюсь с правилом 1 - не определяя значение по умолчанию (независимо от ли it' s инициализированный компилятором или не) Вы оставляете разработчика предположение или идете, ища документацию относительно того, что значение по умолчанию, для которого конкретный язык был бы. В целях удобочитаемости я всегда определял бы значение по умолчанию. – James 10.01.2013, 01:50
  • 3
    Значение по умолчанию типа default(T) всегда является значением, которое имеет внутреннее двоичное представление 0. – Olivier Jacot-Descombes 14.03.2013, 08:26
  • 4
    Технически, все три класса можно было свободно считать функторами, если Вы берете, идут (), чтобы быть классом, обеспеченным функцию вместо оператора (). Сам указатель функции в № 2 не имеет никакого отношения к функторам. Однако только Подход 3 следует за " spirit" из реального функтора C++ и может извлечь выгоду из шаблонной оптимизации, доступной тому, что обычно считают функтором для использования в C++. – Adisak 22.10.2019, 02:22

Семантика C# отличается немного от Java здесь. В присвоении C# в объявлении выполняется прежде, чем назвать конструктора суперкласса. В Java это сразу сделано, после которого позволяет 'этому' использоваться (особенно полезный для анонимных внутренних классов) и означает, что семантика двух форм действительно соответствует.

, Если Вы можете, сделайте полевой финал.

15
ответ дан 04.10.2019, 13:36
  • 1
    @Zan: № 1 предотвращает встроенную оптимизацию также и that' s, что я сравнивал его также. Теперь я добавил опцию № 3 также так или иначе – Thomas Bonini 22.10.2019, 02:22

В C# это не имеет значения. Эти два примера кода, которые Вы даете, совершенно эквивалентны. В первом примере компилятор C# (или действительно ли это - CLR?) создаст пустого конструктора и инициализирует переменные, как будто они были в конструкторе (существует небольшой нюанс к этому, который Jon Skeet объясняет в комментариях ниже). Если уже будет конструктор тогда, то любая инициализация "выше" будет перемещена в вершину его.

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

146
ответ дан 04.10.2019, 13:36
  • 1
    +1 конструктор, объединяющий аргумент в цепочку, силен – annakata 25.03.2009, 22:53
  • 2
    Это не корректно, если Вы принимаете решение инициализировать класс с GetUninitializedObject. То, независимо от того, что находится в ctor, не будет затронуто, но объявления поля будут выполнены. – Wolf5 03.01.2013, 22:18
  • 3
    На самом деле это действительно имеет значение. Если вызовы конструктора базового класса виртуальный метод (который обычно является плохой идеей, но может произойти), который переопределяется в производном классе, то с помощью инициализаторов переменной экземпляра переменная будет инициализирована, когда метод назовут - тогда как с помощью инициализации в конструкторе, они won' t быть. (Инициализаторы переменной экземпляра выполняются прежде , конструктора базового класса вызывают.) – Jon Skeet 13.08.2013, 22:52
  • 4
    Действительно? Я клянусь, что захватил эту информацию от Richter' s CLR через C# (2-й выпуск я думаю) и суть его был то, что это было синтаксическим сахаром (я, возможно, считал его неправильно?) и CLR просто запихнул переменные в конструктора. Но you' ре, указывающее, что этот isn' t случай, т.е. членская инициализация может стрелять прежде ctor инициализация в сумасшедшем сценарии вызова виртуального в основе ctor и наличии переопределения в рассматриваемом классе. Я понимал правильно? Вы просто узнавали это? Озадаченный относительно этого актуального комментария к 5-летнему сообщению (OMG это были 5 лет?). – Quibblesome 14.08.2013, 09:18
  • 5
    Виртуальные функции могут быть по 40x медленнее, когда они предотвращают встраивание небольшой функции, удаление дубликата или невозможные ответвления и/или использование переменного устройства хранения данных только для регистра. – Zan Lynx 22.10.2019, 02:22

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

  • Поля в статических классах/методах
  • Поля, введенные как статичный/заключительный/и др.

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

6
ответ дан 04.10.2019, 13:36
  • 1
    Если копирование указателя функции становится проблемой, указатель функции мог быть абстрагирован в отдельную статическую таблицу, которая является, как v-таблицы обычно работают. – doron 22.10.2019, 02:21

Что, если я сказал Вам, это зависит?

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

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

В системе реального времени, я подвергаю сомнению, нужны ли мне даже переменное или постоянное вообще.

И в C++ я часто не делаю рядом ни с какой инициализацией ни в одном месте и перемещаю его в Init () функция. Почему? Ну, в C++, если Вы инициализируете что-то, что может выдать исключение во время объектной конструкции, которую Вы открываете сами для утечек памяти.

4
ответ дан 04.10.2019, 13:36
  • 1
    Также то, что Adisak заявил о функторах, является хорошей идеей, хотя я не использовал их очень – Charles 22.10.2019, 02:20

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

1
ответ дан 04.10.2019, 13:36
  • 1
    В C# поля всегда устанавливаются значение по умолчанию сначала. Присутствие инициализатора не имеет никакого значения. – Jeffrey L Whitledge 11.05.2010, 08:20

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

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

0
ответ дан 04.10.2019, 13:36

Теги

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