netlib.narod.ru< Назад | Оглавление | Далее >

Конструкторы

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

  struct Date birthdate = { 1953, 2, 2 };

Однако я не рассматривал, можно ли применять этот способ в разных версиях С. Структуры или классы языка C++ можно инициализировать таким образом, но тогда инициализация будет зависеть от количества полей в struct или class и порядка, в котором расположены эти поля, так что это не очень хорошая идея. В С# такая инициализация не допускается. Но было бы очень хорошо, если бы в С# было нечто, позволяющее решать подобные задачи.

Еще один момент. В предыдущей версии программы на С# мы реализовали проверку допустимости значений во всех методах доступа set свойств класса. Однако ситуация, когда класс содержит некорректную дату, по-прежнему возможна — это ситуация, когда объект только что создан:

  Date mydate = new Date();

Можно решить эти две проблемы при помощи средства, называемого конструктором (constructor). Конструктор — это метод класса, выполняемый при создании объекта этого класса. Как видите, после слова new в конструкции:

  Date mydate = new Date();

идет нечто, похожее на вызов метода без параметров. И это так! Это вызов конструктора по умолчанию из класса Date. У каждого класса есть конструктор по умолчанию, существующий независимо от того, определен он явно или нет. Но если явно определить конструктор по умолчанию класса Date, то можно добиться, что объект Date всегда будет содержать допустимую дату.

Можно также определить конструкторы с одним или несколькими параметрами. Например, в классе Date можно определить конструктор с тремя параметрами, который будет инициализировать объект Date конкретной датой. Этот конструктор позволит создавать объект Date таким образом:

  Date birthdate = new Date(1953, 2, 2);

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

Вот простой пример конструктора, параметры которого определяют дату:

  public Date(int year, int month, int day)
  {
      this.year  = year;
      this.month = month;
      this,day   = day;
  }

Но в нем не используется реализованная в свойствах проверка ошибок. Правильнее присвоить значения свойствам, а не полям:

  public Date(int year, int month, int day)
  {
      Year  = year;
      Month = month;
      Day   = day;
  }

Но можно пойти еще дальше. Можно выполнить проверку совместимости трех параметров конструктора.

А как быть с конструктором по умолчанию? Принято определять конструкторы классов по умолчанию, присваивающие объектам нулевые значения или значения, более-менее эквивалентные нулевым. Для класса Date таким значением, вероятно, будет 1 января 1600 года, так как это самая ранняя допустимая дата. Вот новая версия программы:

CsDateConstructors.cs

  //----------------------------------------------------
  // CsDateConstructors.cs (C) 2001 by Charles Petzold
  //----------------------------------------------------
  using System;

  class CsDateProperties
  {
      public static void Main()
      {
          try
          {
              Date mydate = new Date(2001, 8, 29);

              Console.WriteLine("Day of year = " + mydate.DayOfYear);
          }
          catch (Exception exc)
          {
              Console.WriteLine(exc);
          }
      }
  }
  class Date
  {
      // Поля
      public int year;
      public int month;
      public int day;
      static int[] МonthDays = new int[] {   0,  31,  59,  90, 120, 151,
                                           181, 212, 243, 273, 304, 334 };

      // Конструкторы
      public Date()
      {
          Year  = 1600;
          Month = 1;
          Day   = 1;
      }
      public Date(int year, int month, int day)
      {
          if ((month == 2 && IsLeapYear(year) && day > 29) ||
              (month == 2 && !IsLeapYear(year) && day > 28) ||
              ((month == 4 || month == 6 || month == 8 || month == 11) && day > 30))
          {
              throw new ArgumentOfRangeException("Day");
          }
          else
          {
              Year  = year;
              Month = month;
              Day   = day;
          }
      }

      // Свойства
      public int Year
      {
          set
          {
              if (value < 1600)
                  throw new ArgumentOfRangeException("Year");
              else
                  year = value;
          }
          get
          {
              return year;
          }
      }
      public int Month
      {
          set
          {
              if (value < 1 || value > 12)
                  throw new ArgumentOfRangeException("Month");
              else
                  month = value;
          }
          get
          {
              return month;
          }
      }
      public int Day
      {
          set
          {
              if (value < 1 || value > 31)
                  throw new ArgumentOfRangeException("Day");
              else
                  day = value;
          }
          get
          {
              return day;
          }
      }
      public int DayOfYear
      {
          get
          {
              return MonthDays[month - 1] + day +
                                 (month > 2 && IsLeapYear(year) ? 1 : 0);
          }
      }

      // Метод
      public static bool IsLeapYear(int year)
      {
          return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
      }
  };

netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz