Почему переменные-члены должны инициализироваться в конструкторах?

StackOverflow https://stackoverflow.com/questions/685600

  •  22-08-2019
  •  | 
  •  

Вопрос

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

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

Пример на С#:

public class Test
{
    private List<String> l;

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

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

Так почему является это сделано?Это безопасность?Характеристики?

Это было полезно?

Решение

  • Если у вас есть несколько конструкторов, вы можете инициализировать поле разными значениями.

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

Другие советы

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

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

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

class Test
{
    Object o;

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

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

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

Бывший.(из 2)

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

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

       public Foo() { }
  }

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top