Интернет-журнал "Домашняя лаборатория", 2007 №9 - Журнал «Домашняя лаборатория»
Шрифт:
Интервал:
• чтение, запись (Read, Write);
• чтение, запись при первом обращении (Read, Wwrite-once);
• ТОЛЬКО чтение (Read-only);
• ТОЛЬКО запись (Write-only);
• ни чтения, ни записи (Not Read, Not Write).
Открытость свойств (атрибут public) позволяет реализовать только первую стратегию. В языке C# принято, как и в других объектных языках, свойства объявлять закрытыми, а нужную стратегию доступа организовывать через методы. Для эффективности этого процесса и введены специальные методы-свойства.
Приведу вначале пример, а потом уточню синтаксис этих методов. Рассмотрим класс Person, у которого пять полей: fam, status, salary, age, health, характеризующих соответственно фамилию, статус, зарплату, возраст и здоровье персоны. Для каждого из этих полей может быть разумной своя стратегия доступа. Возраст доступен для чтения и записи, фамилию можно задать только один раз, статус можно только читать, зарплата недоступна для чтения, а здоровье закрыто для доступа и только специальные методы класса могут сообщать некоторую информацию о здоровье персоны. Вот как на C# можно обеспечить эти стратегии доступа к закрытым полям класса:
public class Person
{
// поля (все закрыты)
string fam="", status="", health="";
int age=0, salary=0;
//методы — свойства
/// <summary>
/// стратегия: Read,Write-once (Чтение, запись при
/// первом обращении)
/// </summary>
public string Fam
{
set {if (fam == "") fam = value;}
get {return(fam);}
}
/// <summary>
///стратегия: Read-only(Только чтение)
/// </summary>
public string Status
{
get {return(status);}
}
/// <summary>
/// стратегия: Read,Write (Чтение, запись)
/// </summary> public int Age
{
set
{
age = value;
if(age < 7)status ="ребенок";
else if(age <17)status ="школьник";
else if (age < 22)status = "студент";
else status = "служащий";
}
get {return(age);}
}
/// <summary>
/// стратегия: Write-only (Только запись)
/// </summary>
public int Salary
{
set {salary = value;}
}
}
Рассмотрим теперь общий синтаксис методов-свойств. Пусть name — это закрытое свойство. Тогда для него можно определить открытый метод-свойство (функцию), возвращающую тот же тип, что и поле name. Имя метода обычно близко к имени поля (например, Name). Тело свойства содержит два метода — get и set, один из которых может быть опущен. Метод get возвращает значение закрытого поля, метод set — устанавливает значение, используя передаваемое ему значение в момент вызова, хранящееся в служебной переменной со стандартным именем value. Поскольку get и set — это обычные процедуры языка, то программно можно реализовать сколь угодно сложные стратегии доступа. В нашем примере фамилия меняется, только если ее значение равно пустой строке и это означает, что фамилия персоны ни разу еще не задавалась. Статус персоны пересчитывается автоматически при всяком изменении возраста, явно изменять его нельзя. Вот пример, показывающий, как некоторый клиент создает и работает с полями персоны:
public void TestPersonProps ()
{
Person pers1 = new Person();
pers1.Fam = "Петров";
pers1.Age = 21;
pers1.Salary = 1000;
Console.WriteLine ("Фам={0}, возраст={1}, статус={2}",
pers1.Fam, pers1.Age, persl.Status);
pers1.Fam = "Иванов"; pers1.Age += 1;
Console.WriteLine ("Фам={0}, возраст={1}, статус={2}",
pers1.Fam, pers1.Age, pers1.Status);
}//TestPersonProps
Заметьте, клиент работает с методами-свойствами так, словно они являются настоящими полями, вызывая их как в правой, так и в левой части оператора присваивания. Заметьте также, что с каждым полем можно работать только в полном соответствии с той стратегией, которую реализует данное свойство. Попытка изменения фамилии не принесет успеха, а изменение возраста приведет и к одновременному изменению статуса. На рис. 16.1 показаны результаты работы этой процедуры.
Рис. 16.1. Методы-свойства и стратегии доступа к полям
Индексаторы
Свойства являются частным случаем метода класса с особым синтаксисом. Еще одним частным случаем является индексатор. Метод-индексатор является обобщением метода-свойства. Он обеспечивает доступ к закрытому полю, представляющему массив. Объекты класса индексируются по этому полю.
Синтаксически объявление индексатора — такое же, как и в случае свойств, но методы get и set приобретают аргументы по числу размерности массива, задающего индексы элемента, значение которого читается или обновляется. Важным ограничением является то, что у класса может быть только один индексатор и у этого индексатора стандартное имя this. Так что если среди полей класса есть несколько массивов, то индексация объектов может быть выполнена только по одному из них.
Добавим в класс Person свойство children, задающее детей персоны, сделаем это свойство закрытым, а доступ к нему обеспечит индексатор:
const int Child_Max = 20; //максимальное число детей
Person[] children = new Person[Child_Max];
int count_children=0; //число детей
public Person this[int i] //индексатор
{
get {if (i>= 0 && i< count_children)return(children[i]);
else return(children[0]); }
set
{
if (i==count_children && i< Child_Max)
{children[i] = value; count children++;
}
}
Имя у индексатора — this, в квадратных скобках в заголовке перечисляются индексы. В методах get и set, обеспечивающих доступ к массиву children, по которому ведется индексирование, анализируется корректность задания индекса. Закрытое поле count children, хранящее текущее число детей, доступно только для чтения благодаря добавлению соответствующего метода-свойства. Надеюсь, текст процедуры-свойства Count_children сумеете написать самостоятельно. Запись в это поле происходит в методе set индексатора, когда к массиву children добавляется новый элемент.
Протестируем процесс добавления детей персоны и работу индексатора:
public void TestPersonChildren ()
}
Person pers1 = new Person (), pers2 = new Person();
pers1.Fam = "Петров"; persl.Age = 42;
pers1.Salary = 10000;
pers1[pers1.Count_children] = pers2;
pers2.Fam ="Петров"; pers2.Age = 21; pers2.Salary = 1000
Person pers3= new Person("Петрова");
pers1[persl.Count_children] = pers3;
pers3.Fam ="Петрова"; pers3.Age
Поделиться книгой в соц сетях:
Обратите внимание, что комментарий должен быть не короче 20 символов. Покажите уважение к себе и другим пользователям!