Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Инкапсуляция на основе свойств класса



 

Свойства — один из самых замечательных механизмов С# и CLR, который позволяет достичь лучшей инкапсуляции. Если говорить коротко, то свойства используются для ужесточения контроля доступа к внутреннему состоянию объекта.

С точки зрения клиента объекта свойство выглядит и ведет себя аналогично общедоступному полю. Нотация доступа к свойству такая же, как при доступе к общедоступному полю экземпляра. Однако свойство не имеет никакого ассоциированного с ним места хранения в объекте, как это присуще полям. Вместо этого свойство представляет собой сокращенную нотацию для определения средств доступа (accessors) для чтения и записи полей. Типичный шаблон предусматривает обеспечение доступа к приватному полю класса через общедоступное свойство. В С# 3.0 эта задача еще более облегчается за счет введения автореализуемых (auto-implemented) свойств.

Свойства существенно расширяют возможности проектировщиков классов. Например, если свойство представляет количество строк в объекте — таблице базыданных, то этот объект может отложить вычисление этого значения до тех пор, пока оно не будет опрошено свойством. Объект таблицы базы данных узнает, когда необходимо вычислить значение, по факту вызова клиентом средства доступа для обращения к свойству.

В следующем коде определяется свойство Temperature в классе А:

public class A

{

private int temperature;

public int Temperature

{

get

{

System.Console.WriteLine(" Чтение поля temperature" );

return temperature;

}

set

{

System.Console.WriteLine (" Установка поля temperature" );

temperature = value;

}

}

}

public class MainClass

{

static void Main()

{

A obj = new A ();

obj.Temperature = 1;

System.Console.WriteLine ( " obj.Temperature = {0}",

obj.Temperature );

}

}

Сначала определяется свойство по имени Temperature, имеющее тип int. Каждое объявление свойства должно определять тип, представляемый этим свойством. Этот тип должен быть видимым компилятору в точке, где свойство объявлено в классе, и он должен иметь как минимум ту же видимость, что и определяемое свойство. То есть имеется в виду, что если свойство является общедоступным (public), то тип значения, представленного свойством, также должен быть объявлен как public в сборке, в которой он определен. В данном примере тип int — это псевдоним для System. Int32. Этот класс определен в пространстве имен System, и он объявлен как public. Поэтому int можно использовать в качестве типа свойства в данном общедоступном классе А.

Свойство Temperature просто возвращает приватное поле temperature из внутреннего состояния экземпляра объекта. Это — общепринятое соглашение. Приватномуполю назначается имя, начинающееся с прописной буквы, а свойству — имя, начинающееся с заглавной буквы. Разумеется, следовать этому соглашению вовсе не обязательно, но нет причин от него отказываться, к тому же другие программисты С# обычно ожидают его соблюдения.

 

 

Определение типов значений

 

Тип значения — это легковесный тип, который обычно не создается в куче. Единственное исключение из этого правила касается типа значения, которое является полем ссылочного объекта, находящегося в куче. Тип значения — это тип, поведение которого подчиняется семантике значения. То есть когда переменная типа значения присваивается другой переменной типа значения, то содержимое исходной переменной копируется в целевую, причем создается полная копия источника. Это отличает их от ссылочных типов, или экземпляров объектов, где результатом копирования одной переменной ссылочного типа в другую переменную ссылочного типа является новая ссылка на тот же самый объект. При передаче типа значения в качестве параметра методу тело метода получает локальную копию значения, если только параметр не был объявлен как ref или out. Все встроенные типы С# за исключением string, массивов и делегатов, являются типами значений. В С# тип значения объявляется с использованием ключевого слова struct вместо class.

В целом синтаксис определения структуры точно такой же, как у класса, но с рядом заметных исключений, в чем вы вскоре убедитесь. Для структуры нельзя объявлять базовый класс. К тому же структура является неявно герметизированной (sealed). Это значит, что от структуры нельзя ничего унаследовать. Внутренне структура наследуется от класса System.ValueType, который, в свою очередь, расширяет System.Object. Причина в том, что ValueType может предоставлять среди прочих реализации Object. Equals и Object.GetHashCode, что важно для типов значений.

Подобно классам, структуры могут иметь статические конструкторы. Они также могут иметь конструкторы экземпляров, но с одним существенным исключением. Определения структур не могут содержать определяемый по умолчанию конструктор без параметров, а также инициализаторы полей экземпляра. Однако инициализаторы статических полей допускаются. Конструкторы без параметров типам значений не нужны, поскольку система обеспечивает их таковыми, просто устанавливая значения полей в принятые по умолчанию. Во всех случаях все биты таких полей станавливаются в 0. Поэтому, если структура содержит поле int, его значением по умолчанию будет 0. Если структура имеет ссылочное поле, то его значением по умолчанию является null. Каждая структура получает такой неявный конструктор без параметров, который заботится об инициализации. Все это — часть попыток языка по обеспечению генерации верифицируемого и безопасного в отношении типов кода. Переменную типа значения можно объявить без применения ключевого слова new; в таком случае конструктор вообще не вызывается. Тогда ответственность за соответствующую установку данных структуры перед вызовом любых ее методов возлагается на программиста. Рассмотрим следующий код:

using System;

public struct Square

{

// Иметь общедоступные поля - плохая идея, но для примера они здесь

// используются. В реальном коде вместо них должны применяться

свойства.

public int width;

public int height;

}

public class EntryPoint

{

static void Main()

{

Square sq;

sq.width = 1;

// Пока что это делать нельзя.

// Console.WriteLine( " {0} х {1}", sq.width, sq.height );

sq.height = 2;

Console.WriteLine( " {0} x {1}", sq.width, sq.height );

}

}

В методе Main для объекта Square выделяется пространство в стеке. Однако после этого присваивается значение только полю width. Следующий за этим вызов Console. WriteLine помещен в комментарий, поскольку в противном случае код не скомпили- руется. Причина в том, что до полной инициализации структуры ее методы вызывать нельзя. После инициализации поля height можно успешно использовать экземпляр Square для вывода width и height на консоль. Сможете ли вы обнаружить проблему в приведенном ниже коде?

using System;

public struct Square

{

public int Width

{

get

{

return width;

}

set

{

width = value;

}

}

public int Height

{

get

{

return height;

}

set

{

height = value;

}

}

private int width;

private int height;

}

public class EntryPoint

{

static void Main()

{

Square sq;

sq.Width = 1;

sq.Height = 1;

}

}

Проблема кроется в методе Main. Попытка скомпилировать этот код приводит к ошибке. Инициализировать поля нельзя, поскольку они являются private. Также нет возможности инициализировать их через свойства, потому что свойства на самом деле представляют собой вызовы методов, а это не допускается для не полностью инициализированного значения. Один из способов разрубить этот гордиев узел предусматривает использование ключевого слова new в объявлении нового экземпляра Square. При этом можно вызвать либо один из конструкторов структуры, либо конструктор по умолчанию. В данном случае будет вызываться конструктор по умолчанию, так что метод Main изменится следующим образом:

public class EntryPoint

{

static void Main()

{

Square sq = new Square ();

sq.Width = 1;

sq.Height = 1;

}

}

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

 


Поделиться:



Популярное:

  1. IV. Педагогические технологии на основе гуманно-личностной ориентации педагогического процесса
  2. Linux - это операционная система, в основе которой лежит лежит ядро, разработанное Линусом Торвальдсом (Linus Torvalds).
  3. V. Педагогические технологии на основе активизации и интенсификации деятельности учащихся (активные методы обучения)
  4. VI. ИСПРАВЛЕНИЕ РАБОТЫ НА ОСНОВЕ РЕЦЕНЗИЙ
  5. VI. Педагогические технологии на основе эффективности управления и организации учебного процесса
  6. VII. Педагогические технологии на основе дидактического усовершенствования и реконструирования материала
  7. А. Н. Леонтьев, А. В. Запорожец, В. П. Зинченко Формирование перцептивных механизмов и предметных образов на основе внешних ориентировочно-исследовательских операций и действий субъекта
  8. А. Общие транспортные характеристики и свойства наливных грузов.
  9. А. ХАРАКТЕРНЫЕ СВОЙСТВА КАЖДОГО ОРГАНА
  10. А.2 Защита от косвенного прикосновения
  11. Автоматическое создание методов для свойств объектов
  12. Акустические свойства звуков речи


Последнее изменение этой страницы: 2016-05-03; Просмотров: 660; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.033 с.)
Главная | Случайная страница | Обратная связь