
- •Лекции по курсу "Технология программирования" (1-й семестр) Оглавление
- •Технология .Net Предыдущее состояние дел.
- •Главные компоненты платформы .Net (clr, cts и cls)
- •Общеязыковая среда выполнения (clr)
- •О бщая система типов и общеязыковые спецификации (cts и cls)
- •Библиотека базовых классов
- •Роль языка с#
- •Компоновочные блоки
- •Роль метаданных типов .Net
- •Роль манифеста компоновочного блока
- •Общая система типов.
- •Объектно-ориентированное программирование
- •Главные элементы объектно-ориентированного подхода
- •Дополнительные элементы ооп
- •Принципы объектно-ориентированного программирования.
- •Классы Инкапсуляция
- •Объект (экземпляр класса).
- •Ключевое слово this
- •Отношения между объектами.
- •Основные отличительные особенности класса
- •Спецификаторы доступа
- •Состав класса
- •Поля класса
- •Доступ к полям
- •Статические и экземплярные переменные
- •Методы (функции-члены класса)
- •Переменное число параметров метода
- •Статические методы
- •Конструкторы
- •Закрытые конструкторы или классы без экземпляров
- •Статические конструкторы.
- •Деструкторы
- •Абстрактные методы и классы.
- •Свойства
- •Индексаторы
- •Статические классы
- •Частичные классы
- •Рекомендации по программированию
- •Наследование Понятие наследования в программировании
- •Типы наследования
- •Наследование реализации
- •Определение наследующих классов
- •Уровень доступа protected и internal
- •Ссылка на объект базового класса
- •Протоклассы
- •Предотвращение наследования с помощью ключевого слова sealed.
- •Отношения между классами
- •Абстрактные классы.
- •Класс object
- •Функциональные замыкания
- •Разработка функциональных замыканий с помощью наследования
- •Разработка функциональных замыканий с помощью экземпляров класса
- •Заключение.
- •Полиморфизм
- •Полиморфизм наследующих классов.
- •Переопределение методов родительского класса. Раннее связывание.
- •Виртуальные методы и их переопределение.
- •Как вызывают виртуальные методы
- •Виртуальные функции и принцип полиморфизма
- •Перегрузка.
- •Перегруженные конструкторы
- •Рекомендации программисту.
Свойства
Свойства расширяют возможности полей данных. Они представляют собой типизированные объекты, у которых можно получить значение и записать в них новое значение. При выполнении этих действий выполняется определяемый программистом код. Синтаксис определения полей следующий:
<модификаторы> <тип> <имя>
{
get { /* Тело get */ }
set { /* Тело set */ }
}
В теле get пишется код, который выполняется при получении значения свойства. В теле set пишется код, который выполняется при установке нового значения. При этом в set доступно присваеваемое значение через ключевое слово value:
public class SampleClass
{
private static int a;
public static int A
{
get { return a; }
set { a = value; }
}
public static void Main() { A = 2; Console.WriteLine("A = {0}", A); }
}
Этот пример демонстрирует распространенный прием инкапсуляции полей.
Свойство – это пара методов со специальными именами. Метод set() вызывается при изменении значения свойства, метод get() – при получении значения свойства. Обращение к свойству выглядит как обращение к полю данных, но транслируется в вызов одного из двух методов. Имя метода обычно близко к имени поля (например, если имя переменной - name, то свойству дают имя - Name).
Каждый из методов свойства: set() и get() может иметь свой собственный модификатор доступа. При работе со свойствами часто нужно решить, какой модификатор доступа следует использовать для того, чтобы реализовать нужную стратегию доступа к полю класса. Существует пять наиболее употребительных стратегий:
* чтение и запись (Read, Write); * чтение и запись только при первом обращении (Read, Write-once); * только чтение (Read-only); * только запись (Write-only); * ни чтения, ни записи (Not Read, Not Write).
Открытость свойств (атрибут public) позволяет реализовать только первую стратегию.
class PropertyClass1
{
private int x;
public int X
{
set { x=value; }
get { return x; }
}
}
Определяя в свойстве только один из двух методов, получаем свойства только для чтения или только для записи.
// Стратегия только чтения или только записи
class PropertyClass1
{
private int x, y;
public int X { get { return x; } }
public int Y { set { y=value; } }
}
Однако, возможен и другой вариант реализации той же стратегии, использующий манипуляцию уровнями доступа к методам, реализующим свойство:
// Та же стратегия - только чтения или только записи
class PropertyClass1
{
private int x, y;
public int X
{
private set { x=value; }
get { return x; }
}
public int Y
{
set { y=value; }
private get { return x; }
}
}
Индексаторы
Одним из важных направлений развития языков программирования является удобство и наглядность кода. Именно стремление упростить структуру кода привело в свое время к перегрузке операторов в С++ и свойств в Object Pascal. Предлагая новый язык специально для своей новой платформы, Microsoft, разумеется, не могла не учесть это сторону вопроса. Поэтому язык включает в себя свойства (properties) и индексаторы (indexers).
При написании приложений часто возникает необходимость создавать объекты, представляющие собой коллекцию других объектов (они не обязательно могут явно хранить в себе все эти объекты, а только предоставлять доступ к ним). В языках вроде Cи или Java для этого использовались специальные функции (методы) вроде GetItem( int index ). Конечно, это возможный подход, но часто, когда нужно часто обращаться к элементам коллекции, неудобно каждый раз писать такие громоздкие конструкции.
Свойство, обеспечивающее доступ к массиву, называется индексатор. Синтаксически объявление индексатора - такое же, как и в случае свойств, но методы get и set приобретают аргументы по числу размерности массива, задающего индексы элемента, значение которого читается или обновляется. Важным ограничением является то, что у класса может быть только индексатор со стандартным именем this.
Индексаторы предоставляют синтаксис сходный с тем, который используется при адресации массива, за исключением того, что в качестве типа данных индекса, можно использовать любой тип. Для того, чтобы объявить в классе индексатор, нужно использовать следующий синтаксис:
<тип> this [список_параметров]
где тип – это тип возвращаемого значения (тип элемента коллекции), а список параметров – это типы и имена параметров, используемых для идентификации элемента коллекции. Индексатор может иметь любые модификаторы, кроме static, а к его параметрам нельзя применять модификаторы out и ref.
Для определения кода индексатора, нужно прописать ему метода доступа - get и, возможно, set (если индексатор у вас позволяет менять элементы). При этом в методе get доступны все параметры индексатора как переменные, а в методе set дополнительно к ним параметр value, представляющий новое значение элемента. Таким образом, индексатор примет вид, аналогичный следующему:
public object this [int index]
{
get { return GetItem(index); }
set { SetItem(index, value); }
}
Для полной ясности картины, приведем небольшой пример:
using System;
public CustomIndexerClass
{
// Объявляем внутренний массив, где будут храниться действительные значения
private int internalArray = new int[10];
// Объявляем индексатор
public int this [int index]
{
get // Доступ на чтение
{
// Проверка границ
if (index < internalArray.GetLowerBound(0) ||
index > internalArray.GetUpperBound(0))
return 0;
// Вoзвращаем значение соответствующего элемента массива
return internalArray[index];
}
set
{
// Проверка границ и запись нового значения
if (index >= internalArray.GetLowerBound(0) &&
index <= internalArray.GetUpperBound(0))
internalArray[index] = value;
}
}
public class ApplicationClass
{
public static void Main()
{
CustomIndexerClass myIndexer = new CustomIndexerClass();
myIndexer[1] = 10;
myIndexer[5] = 7;
for (int i = 0; i < 10; i++)
Console.WriteLine("myIndexer[{0}] = {1}\n", i, myIndexer[i]);
}
}
}
Эта программа создает класс, имеющий индексатор, который просто читает или записывает значения во внутреннем массиве. Главная программа сначала изменяет несколько ячеек массива, пользуясь индексатором, а затем читает все его ячейки последовательно.