Интернет-журнал "Домашняя лаборатория", 2007 №9
Шрифт:
Методы класса
Методы класса синтаксически являются обычными процедурами и функциями языка. Их описание удовлетворяет обычным правилам объявления процедур и функций, о чем подробно говорилось в лекции 9. Содержательно методы определяют ту самую абстракцию данных, которую реализует класс. Методы содержат описания операций, доступных над объектами класса. Два объекта одного класса имеют один и тот же набор методов.
Доступ к методам
Каждый метод имеет модификатор доступа, принимающий одно из четырех значений: public, private, protected, internal.
Если некоторые методы класса а должны быть доступны для вызовов в методах класса B, являющегося потомком класса A, то такие методы следует снабдить атрибутом protected. Если некоторые методы должны быть доступны только для методов классов B1, В2 и так далее, дружественных по отношению к классу A, то такие методы следует снабдить атрибутом internal, а все дружественные классы в поместить B один проект. Наконец, если некоторые методы должны быть доступны для методов любого класса в, которому доступен сам класс A, то такие методы снабжаются модификатором public.
Методы-свойства
Методы, называемые свойствами (Properties), представляют специальную синтаксическую конструкцию, предназначенную для обеспечения эффективной работы со свойствами. При работе со свойствами объекта (полями) часто нужно решить, какой модификатор доступа использовать, чтобы реализовать нужную стратегию доступа к полю класса. Перечислю пять наиболее употребительных стратегий:
• чтение, запись (Read, Write);
• чтение, запись при первом обращении (Read, Wwrite-once);
• ТОЛЬКО чтение (Read-only);
• ТОЛЬКО запись (Write-only);
• ни чтения, ни записи (Not Read, Not Write).
Открытость свойств (атрибут public) позволяет реализовать только первую стратегию. В языке C# принято, как и в других объектных языках, свойства объявлять закрытыми, а нужную стратегию доступа организовывать через методы. Для эффективности этого процесса и введены специальные методы-свойства.
Приведу вначале пример, а потом уточню синтаксис этих методов. Рассмотрим класс Person, у которого пять полей: fam, status, salary, age, health, характеризующих соответственно фамилию, статус, зарплату, возраст и
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 показаны результаты работы этой процедуры.