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

Получение и присваивание значений свойств

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

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

Некоторые программисты на С# (в том числе и я) дают закрытым полям имена, начинающиеся со строчных букв, а открытым свойствам — имена, начинающиеся с заглавных букв. Ниже приведено простейшее определение свойства Month обеспечивающего доступ к закрытому полю month:

  public int Month
  {
      set
      {
          month = value;
      }
      get
      {
          return month;
      }
  }

Программа, использующая класс с таким свойством, обращается к свойству точно так же, как если бы это было поле:

  mydate.Month = 7;

или:

  Console.WriteLine(mydate.Month);

или:

  mydate.Month += 2;

В последнем примере значение Month увеличивается на 2. Смотрите, насколько синтаксис этого оператора прозрачнее, чем синтаксис аналогичного оператора, использующего методы SetMonth и GetMonth, с которыми мы работали ранее:

  mydate.SetMonth(mydate.GetMonth() + 2); // Хорошо, что мы от этого
                                          // избавились!

Рассмотрим определение этого свойства подробно. Ключевое слово public означает, что это свойство доступно вне класса. Тип данных int — что свойство является 32-битным целым. Само свойство имеет имя Month.

Внутри тела свойства содержатся два метода доступа (accessors) — set и get. He обязательно использовать оба. У многих свойств есть только открытый метод доступа get, a set или вообще не определен, или определен как private. Такие свойства называются неизменяемыми (read-only). Можно также создать свойство с методом доступа set и без метода доступа get, но это требуется гораздо реже.

Внутри определения метода доступа set специальное слово value служит для указания значения, присваиваемого свойству инструкцией:

  mydate.Month = 7;

Метод доступа get всегда должен содержать инструкцию return, чтобы вернуть значение программе, использующей свойство.

Следующая программа использует свойства Year, Month и Day и выполняет в методах доступа set проверку допустимости значений.

CsDateProperties.cs

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

  class CsDateProperties
  {
      public static void Main()
      {
          Date mydate = new Date();

          try
          {
              mydate.Month = 8;
              mydate.Day   = 29;
              mydate.Year  = 2001;

              Console.WriteLine("Day of year = {0}", 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 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));
      }
  };

Я оставил код в блоках try и catch, так что вы можете поэкспериментировать с некорректными датами. Кстати, для свойства Year я установил минимальное значение 1600, так как для более ранних дат метод IsLeapYear не имеет особого смысла. Осталась нерешенной одна проблема: метод не проверяет согласованность полей между собой. Например, можно задать дату 31 февраля. Такая проверка согласованности наложила бы ограничения на порядок присвоения свойств, так что я обойдусь без нее.

Кроме того, я преобразовал DayOfYear из метода в неизменяемое свойство, потому что значение дня года больше похоже на свойство даты, чем на метод. Иногда бывает сложно определить, что использовать — метод или свойство? Единственное очевидное правило: есть параметр — используй метод.


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

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