Почему переменные-члены должны быть инициализированы в конструкторах? - PullRequest
5 голосов
/ 26 марта 2009

Когда я впервые начал работать с объектно-ориентированными языками программирования, меня учили следующему правилу:

При объявлении поля в классе еще не инициализируйте его. Сделайте это в конструкторе.

Пример в C #:

public class Test
{
    private List<String> l;

    public Test()
    {
        l = new List<String>();
    }
}

Но когда кто-то недавно спросил меня, зачем это делать, я не смог придумать причину. Я не очень знаком с внутренней работой C # (или других языков программирования, в этом отношении, поскольку я полагаю, что это может быть сделано на всех языках OO).

Так почему это это сделано? Это безопасность? Свойства?

Ответы [ 6 ]

14 голосов
/ 26 марта 2009
  • Если у вас есть несколько конструкторов, вы можете инициализировать поле другими значениями

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

10 голосов
/ 26 марта 2009

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

class Test
{
    Object o = new Object();
}

компилируется в это:

class Test
{
    Object o;

    public Test()
    {
        this.o = new Object();
    }
}

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

2 голосов
/ 26 марта 2009

Одна из причин этого заключается в том, что он помещает весь код инициализации в одно место, что удобно для других, читающих ваш класс. Сказав это, я не делаю этого по двум основным причинам. (1) Я использую тестирование TDD / Unit, чтобы определить поведение моего класса. Если вы хотите знать, что делает конструктор без параметров, вам действительно следует прочитать тесты, которые я построил на конструкторе без параметров. (2) В C # 3.0 я обычно использую автоматические свойства и встроенную инициализацию с помощью конструктора без параметров, чтобы создать экземпляр объекта. Это намного более гибко, и оно помещает определение свойств прямо в строку, где используется код. Это переопределит любую инициализацию в конструкторе, поэтому я редко помещаю их туда. Конечно, это относится только к C #.

Ex. (из 2)

  var foo = new Foo { Bar = "baz" };

  public class Foo
  {
       public string Bar { get; set; }

       public Foo() { }
  }
1 голос
/ 26 марта 2009

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

0 голосов
/ 26 марта 2009

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

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

0 голосов
/ 26 марта 2009

Я не слышал убедительной причины не предлагать оба варианта. Я подозреваю, что настоящая причина связана с упрощением языковой структуры с точки зрения анализа. Это особенно верно в C-производных языках, где для синтаксического анализа оператора присваивания требуется 75% правил синтаксиса языка. Мне кажется, что было бы неплохо разрешить и определить, как именно это будет работать. Я согласен с комментарием Майкла об увеличении сложности при вставке наследования и нескольких конструкторов, но только то, что вы добавляете функцию, не означает, что вы должны ее использовать. Я бы проголосовал за то, чтобы поддержать и то и другое, хотя мой голос на самом деле мало что значит.

...