Неправильная практика - инициализировать поля вне явного конструктора

Возможный дубликат:
Инициализировать поля класса в конструкторе или объявлении?

Мы спорим о практике кодирования. Примеры здесь немного слишком просты, но в реальной сделке есть несколько конструкторов. Чтобы инициализировать простые значения (например, даты до их значения min), я переместил код из конструкторов и в определения полей.

public class ConstructorExample
{
    string _string = "John";
}

public class ConstructorExample2
{
    string _string;

    public ConstructorExample2()
    {
        _string = "John";
    }
}

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

Вопрос в основном... инициализирует поля, в которых они определены, в отличие от конструктора, каким-либо образом?

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

Ответ 1

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

 string _string;

    public ConstructorExample2()
    {
        _string = "John";
    }

Это то, что если у вас есть несколько конструкторов, вы должны помнить либо  1. Reinitialize _string в каждом конструкторе
 2. Разделите логику на общий метод и вызовите этот метод в каждом конструкторе
 3. Вызовите конструктор с логикой в ​​нем, от других конструкторов. (Цепочка конструкторов)
Теперь это не обязательно проблема, но вы должны помнить об этом. Инициализируя его вне конструктора, это было сделано для вас. Это еще одна вещь, которую вам нужно запомнить.

Ответ 2

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

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

Посмотрите на этот пример:

using System;

namespace ClassLibrary3
{
    public class Class1
    {
        private string _Name = "Lasse";

        public Class1()
        {
        }

        public Class1(int i)
            : this()
        {
        }

        public Class1(bool b)
        {
            _Name = "Test";
        }
    }
}

Этот код компилируется следующим образом:

using System;

namespace ClassLibrary3
{
    public class Class1
    {
        private string _Name;

        public Class1()
        {
            _Name = "Lasse"
        }

        public Class1(int i)
            : this()
        {
            // not here, as this() takes care of it
        }

        public Class1(bool b)
        {
            _Name = "Lasse"
            _Name = "Test";
        }
    }
}

Ответ 3

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

Со статическими классами вам нужно будет отметить некоторые тонкости, рассмотренные в этом вопросе.

Ответ 4

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

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

Когда код скомпилирован, оба подхода будут одинаковыми в любом случае.

Ответ 5

Не уверен в С#, но в исходном коде Java они предпочитают конструктор, например:

public class String{
    char[] value;
    int offset;
    ...
    public String(){
        value = new char[0];
        offset = 0;
        ...
    }
} 

Ответ 6

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

Ответ 7

Я стараюсь инициализировать вещи в get accessor, где они сначала используются. Если null, то инициализируйте и все это.

Ответ 8

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

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

Ответ 9

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

Ответ 10

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