Свойства

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

Свойство — это особый вид методов, обеспечивающих доступ к полям класса. Для каждого свойства может быть два таких метода: один — для чтения значения поля (get), другой — для записи в него какого-то значения (set). В свойстве могут быть определены оба метода или только какой-либо один. Как правило, одно свойство используют для доступа только к одному полю. Ни для каких других задач свойства не рекомендуется применять.

Формальная запись объявления свойства имеет следующий вид:

Доступ Тип Имя_свойства

{

   get

   {

      return Результат

   }

   set

   {

      Поле_класса = value;

   }

}

Использование свойства в программе:

Имя_объекта_класса.Имя_свойства = Выражение;

или

Переменная = Имя_объекта_класса.Имя_свойства;

Здесь

Доступ — обычно это слово public (общий доступ), но допустимо использовать protected, private, internal, а также static и new;

Тип — тип свойства. Должен совпадать с типом поля, с которым связано свойство;

Имя_свойства — задаётся по общим правилам для идентификаторов;

get — ключевое слово, оно определяет метод для получения (чтения) значения;

set — ключевое слово, оно определяет метод для изменения (записи) значения;

value — ключевое слово, используется в методе set как неявный параметр и содержит значение, которое необходимо присвоить полю;

Результат — обычно это значение поля класса (у нас далее обозначается как Поле_класса), связанного со свойством;

Переменная и Выражение — должны иметь тот же тип, что и тип свойства.

Для большей ясности приведём пример простой программы, использующей класс со свойством.

Пример. Для класса, моделирующего работу с окружностью, создадим свойство для изменения радиуса окружности.

Возможный текст программы:

using System;

namespace Prim_Svojstvo

{

   public class Okr

   {

      int x, y, r; // координаты центра окружности и её радиус

      public Okr()

      {

         x = y = 100;

         r = 10;

      }

      public Okr(int x0, int y0, int r0)

      {

         x = x0;

         y = y0;

         r = r0;

      }

      public void print()

      {

         Console.WriteLine("x = {0} y = {1} r = {2}", x, y, r);

      }

      public int Radius

      {

         set

         {

            if(value > 0)

               r = value;

            else

            {

               Console.WriteLine("Недопустимое значение для поля: {0}", value);

               Console.WriteLine("Поле сохраняет прежнее значение: {0}", r);

            }

         }

         get

         {

            return r;

         }

      }

   }

   class Program

   {

      public static void Main(string[] args)

      {

         Okr x = new Okr(25, 45, 5);

         x.print();

         x.Radius = 4;

         x.print();

         int r2 = x.Radius * 2;

         Console.WriteLine("Удвоенное значение радиуса r2 = {0}", r2);

         Console.Write("Press any key to continue . . . ");

         Console.ReadKey(true);

      }

   }

}

Результат выполнения программы:

x = 25 y = 45 r = 5

x = 25 y = 45 r = 4

Удвоенное значение радиуса r2 = 8

Press any key to continue . . .

Пояснение к программе. В данной программе использовано свойство Radius, которое обеспечивает полный доступ к закрытому полю r. При необходимости можно было бы определить для данного свойства только метод set (обеспечиваем доступ по записи) или только метод get (доступ только по чтению). Применяется свойство в методе Main() точно также, как если бы это было поле.

Каков смысл в использовании свойств? Какие преимущества получает программист, применяющий в тексте своей программы свойства?

Свойства применяют для доступа к полям, которые, как правило, всегда делают закрытыми (private) или защищёнными (protected).

Возникает вопрос: а не проще ли тогда сделать поле открытым (public), да и обращаться к полю везде, где это потребуется? Да, проще, но в этом случае заметно снижается безопасность данных. Именно для того, чтобы случайно не изменить поле, его и делают закрытым (меньше возможностей по изменению поля — менее вероятна неверная, случайная модификация данных). К тому же, если требуется доступ к полю только по чтению, зачем его делать открытым (доступным и по чтению, и по записи)?

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

int getRadius()

{

   return r;

}

Понадобился бы метод для доступа по записи — можно добавить ещё метод

void setRadius(int r0)

{

   if(r0 > 0)

      r = r0;

   else

   {

      Console.WriteLine("Недопустимое значение для поля: {0}", r0);

      Console.WriteLine("Поле сохраняет прежнее значение: {0}", r);

   }

}

Хорош такой подход к решению проблемы? Вполне. Безопасность поля обеспечена, обеспечена гибкость при доступе к данным: можно сделать доступ по чтению-записи, используя оба метода, или только по чтению (в классе есть только метод getRadius()), или только по записи (в классе имеется только метод setRadius(int r0)).

А в чём недостаток этого подхода? Во-первых, увеличивается количество имён (для работы с одним полем надо пользоваться двумя разными методами), а чем больше разных имён в программе, тем сложнее с ней работать. Во-вторых, для обращения к полям используется функциональный способ (явный вызов методов), что менее удобно, чем обращение к переменным или к полям, где применяется операторная форма записи.

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

r2 = x.Radius * 2;

выглядит более естественно, чем оператор с вызовом метода

r2 = x.getRadius() * 2;

Возникает вопрос: есть ли недостатки у свойств? На примере нашего свойства Radius можно сказать следующее: относительно отдельных методов типа getRadius() и setRadius(), свойство Radius, естественно, недостатков не имеет, а вот относительно непосредственного обращению к полю r — да, имеет. Главное — доступ к полю напрямую осуществляется гораздо быстрее, чем с использованием свойства. Но достоинства свойств с лихвой перевешивают этот недостаток.

Назад
На верх
Вперёд
Hosted by uCoz