2016-04-13 3 views
5

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

По умолчанию в C# создается пустой конструктор по умолчанию, если в классе не указаны конструкторы.

Большинство примеров, которые я нахожу, указываю что-то вроде этого;

public Car(int speedCurrent, int gearCurrent) { 
    speed = speedCurrent; 
    gear= startGear; 
} 

Car myCar = new Car(0, 0); 

Теперь, что является практическим пунктом создания конструктора, когда вы можете указать свойства;

public int speed { get; set; } 
public int gear { get; set; } 

И инициализируйте его следующим образом;

Car myCar = new Car(); 
myCar.speed = 0; 
myCar.gear = 0; 

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

+0

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

+0

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

+0

Чистый, легко читаемый код. Одна из самых важных причин, которые вы уже дали себе, обеспечивая правильную инициализацию. Если метод использует правильно заданные поля и свойства, ему нужен хороший конструктор. Но если вы собираетесь устанавливать свойства после инициализации, также проверьте это для лучшей читаемости https://msdn.microsoft.com/en-us/library/bb384062.aspx – ikkentim

ответ

4

Теперь, в чем практическая точка создания конструктора, когда вы можете указать свойства;

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

10

Хотя вы можете инициализировать свойства, как то, что вы показываете:

Car myCar = new Car(); 
myCar.speed = 0; 
myCar.gear = 0; 

без конструктора, вы можете также выбрать не инициализировать какой-либо из свойств

Car myCar = new Car(); 

Что может вызвать класс плохо работать/вообще не работать.

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

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

1

Практическая точка в вашем примере является то, что вам не нужно делать new Car(0, 0); для инстанцировании, но вместо того, чтобы просто сделать это для инициализации по умолчанию:

public Car() { 
    speed = 0; 
    gear = 0; 
} 

Car myCar = new Car(); 
1

Non конструктор по умолчанию принудительно клиент вашего класса предоставить параметры.Инициализация по свойствам a) не требуется по коду b) может предоставить класс, еще не готовый к использованию. Кроме того, вы можете скрыть свойства скорости или передачи от других.

1

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

1

Проблема в том, что вашим пользователям класса Car необходимо как-то знать, что им необходимо установить начальную скорость и передачу автомобиля.

Руководящий принцип правила i заключается в том, что конструктор должен создать объект, который на 100% готов к использованию.

2

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

Есть четыре проблемы, связанные с подходом, который предоставляет свойство:

  • Вы не можете обеспечить согласованность после инициализация - Например, если вы хотите удостовериться, что для ненулевой скорости требуется ненулевая передача, вы больше не можете контролировать эту проверку
  • Вы не можете обеспечить согласованность, когда несколько атрибутов должны обновляться атомарно - В параллельных ситуациях, когда оба speed и gear должны обновляться одновременно охранял замком подходе с независимо друг от друга открытых атрибутов не будет надежным
  • Вы вынуждены сделать свой объект изменчивым.. Это не всегда желательно, особенно если ваш объект предназначен для одновременного использования.
  • Вы вынуждены раскрывать методы, которые могут вам не нужны ваши пользователи - Даже в ситуациях, когда ваши пользователи ожидают изменчивый объект может быть нежелательным, чтобы разоблачить отдельные сеттеры; при таком подходе у вас нет другого выбора.

Я не могу обернуть мою голову вокруг необходимости имея явное создание конструктора.

Вот краткая демонстрация того, что вы можете сделать, когда ваши сеттера не подвергаются:

class Car { 
    private readonly object lockObject = new object(); 
    private int speed; 
    private int gear; 
    public int Speed { 
     lock (lockObject) { 
      return speed; 
     } 
    } 
    public int Gear { 
     lock (lockObject) { 
      return gear; 
     } 
    } 
    public int Gear{ get; } 
    public Car(int speed, int gear) { 
     // You can validate two attributes together 
     if (speed != 0 && gear == 0) { 
      throw new ArgumentException("Non-zero speed in zero gear"); 
     } 
     this.speed = speed; 
     this.gear= gear; 
    } 
    public void SpeedUp(int increase) { 
     lock(lockObject) { 
      var newSpeed = Math.Max(Speed + increase, 0); 
      if (newSpeed > 200) { 
       throw new InvalidOperationexception("Cannot speed up past 200"); 
      } 
      // Concurrent users would not see inconsistent speed setting 
      Speed = newSpeed; 
      Gear = Speed/25; 
     } 
    } 
} 

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

1

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

Современные кодеры избегают конструкторов, которые принимают параметры. Это связано с трудностями, которые они вызывают при проведении автоматических модульных испытаний. Вполне нормально использовать классы, которые имеют только конструкторы по умолчанию (конструкторы без аргументов) и инициализировать их с помощью вызовов свойств или методов после факта.

+0

Я никогда не слышал об этой причине, чтобы избежать конструкторов с параметрами. В чем проблема с автоматическим тестированием, о котором вы упоминаете? –

+0

[ссылка] (http://www.codeproject.com/Articles/71908/Unit-testing-and-the-constructors-do-nothing-rule) –

+0

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

1

Я бы сказал, что это приведет к тому, как вы хотите достичь цели класса, который вы строите.

В программировании OO для достижения инкапсуляции вы можете получить доступ только к членам через getters/seters. Опять же, это зависит от того, как далеко вы хотите пойти с реализацией принципов OO.

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

private int speed { get; set; } 
private int gear { get; set; } 
private bool reduceSpeed { get; set; } 

public Car(int speedCurrent, int gearCurrent) { 
    speed = speedCurrent; 
    gear= startGear; 
    if (speed > 30) 
     reduceSpeed = true; // do further processing with this. 
    ... 
}