Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Индексаторы и свойства.docx
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
82 Кб
Скачать
☆

10.2.3 Ограничения, присущие свойствам

Свойствам присущ ряд существенных ограничений. Во-первых, свойство не опреде­ляет место для хранения данных, и поэтому не может быть передано методу в качестве параметра ref или out. Во-вторых, свойство не подлежит перегрузке. Наличие двух разных свойств с доступом к одной и той же переменной допускается, но это, скорее, исключение, чем правило. И наконец, свойство не должно изменять состояние базо­вой переменной при вызове аксессора get. И хотя это ограничительное правило не соблюдается компилятором, его нарушение считается семантической ошибкой. Дей­ствие аксессора get не должно носить характер вмешательства в функционирование переменной.

10.3 Применение модификаторов доступа в аксессорах

По умолчанию доступность аксессоров set и get оказывается такой же, как и у индексатора и свойства, частью которых они являются. Так, если свойство объявляется как public, то по умолчанию его аксессоры set и get также становятся открытыми (public). Тем не менее для аксессора set или get можно указать собственный мо­дификатор доступа, например private. Но в любом случае доступность аксессора, определяемая таким модификатором, должна быть более ограниченной, чем доступ­ность, указываемая для его свойства или индексатора.

Существует целый ряд причин, по которым требуется ограничить доступность ак­сессора. Допустим, что требуется предоставить свободный доступ к значению свойства, но вместе с тем дать возможность устанавливать это свойство только членам его класса. Для этого достаточно объявить аксессор данного свойства как private. В приведен­ном ниже примере используется свойство MyProp, аксессор set которого указан как private.

Листинг 10.9

// Применить модификатор доступа в аксессоре

using System;

class PropAccess

{

int prop; // Поле, управляемое свойством MyProp

public PropAccess() { prop = 0; }

/* Это свойство обеспечивает доступ к закрытой переменной

экземпляра prop. Оно разрешает получать значение переменной

prop из любого кода, но устанавливать его – только

членам своего класса. */

public int MyProp

{

get {

return prop;

}

private set { // теперь это закрытый аксессор

prop = value;

}

}

// Этот член класса инкременирует значение свойства MyProp.

public void IncrProp() {

MyProp++; // Допускается в том же самом классе

}

}

// Продемонстрировать применение модификатора доступа в аксессоре

// свойства

class PropAccessDemo

{

static void Main()

{

PropAccess ob = new PropAccess();

Console.WriteLine("Первоначальное значение ob.MyProp: " +

ob.MyProp);

// ob.MyProp = 100; // Недоступно для установки

ob.IncrProp();

Console.WriteLine("Значение ob.MyProp после инкременирования:"

+ ob.MyProp);

}

}

В классе PropAccess аксессор set указан как private. Это означает, что он досту­пен только другим членам данного класса, например методу IncrProp(), но недосту­пен для кода за пределами класса PropAccess. Именно поэтому попытка Присвоить свойству ob.MyProp значение в классе PropAccessDemo закомментировано.

Вероятно, ограничение доступа к аксессорам оказывается наиболее важным для работы с автоматически реализуемыми свойствами. Как пояснялось выше, создать автоматически реализуемое свойство только для чтения или же только для записи нельзя, поскольку оба аксессора, get и set, должны быть указаны при объявлении такого свойства. Тем не менее добиться желаемого результата все же можно, объявив один из аксессоров автоматически реализуемого свойства как private. В качестве примера ниже приведено объявление автоматически реализуемого свойства Length для класса FailSoftArray, которое фактически становится доступным только для чтения.

public int Length { get; private set; }

Свойство Length может быть установлено только из кода в его классе, поскольку его аксессор set объявлен как private. А изменять свойство Length за пределами его класса не разрешается. Это означает, что за пределами своего класса свойство, по существу, оказывается доступным только для чтения. Аналогичным образом можно объявить и свойство Error, как показано ниже.

public bool Error { get; private set; }

Благодаря этому свойство Error становится доступным для чтения, но не для уста­новки за пределами класса FailSoftArray.

Для опробования автоматически реализуемых вариантов свойств Length и Error в классе FailSoftArray удалим сначала переменные len и ErrFlag, поскольку они больше не нужны, а затем заменим каждое применение переменных len и ErrFlag свойствами Length и Error в классе FailSoftArray. Ниже приведен обновленный вариант класса FailSoftArray вместе с методом Main(), демонстрирующим его применение.

Листинг 10.10

// Применить автоматически реализуемые и доступные

// только для чтения свойства Length и Error

using System;

class FailSoftArray

{

int[] a; // ссылка на базовый массив

// Построить массив по заданному размеру

public FailSoftArray(int size)

{

a = new int[size];

Length = size;

}

// Автоматически реализуемое и доступное только для чтения

// свойство Length

public int Length { get; private set; }

// Автоматически реализуемое и доступное только для чтения

// свойство Error

public bool Error { get; private set; }

// Этот индексатор для массива FailSoftArray

public int this[int index]

{

// Это аксессор get

get

{

if(ok(index))

{

Error = false;

return a[index];

}

else

{

Error = true;

return 0;

}

}

// Это аксессор set

set

{

if(ok(index))

{

a[index] = value;

Error = false;

}

else Error = true;

}

}

// Возвратить логическое значение true, если

// индекс находится в установленных границах

private bool ok(int index)

{

if(index >= 0 & index < Length) return true;

return false;

}

}

// Продемонстрировать применение усовершенствованного

// отказоустойчивго массива

class FinalFSDemo

{

static void Main()

{

FailSoftArray fs = new FailSoftArray(5);

// Использовать свойство Error

for(int i=0; i < fs.Length + 1; i++) {

fs[i] = i*10;

if(fs.Error)

Console.WriteLine("Ошибка в индексе " + i);

}

}

}

Этот вариант класса FailSoftArray действует таким же образом, как и предыду­щий, но в нем отсутствуют поддерживающие поля, объявляемые явно.

На применение модификаторов доступа в аксессорах накладываются следующие ограничения. Во-первых, действию модификатора доступа подлежит только один ак­сессор: set или get, но не оба сразу. Во-вторых, модификатор должен обеспечивать более ограниченный доступ к аксессору, чем доступ на уровне свойства или индексато­ра. И наконец, модификатор доступа нельзя использовать при объявлении аксессора в интерфейсе или же при реализации аксессора, указываемого в интерфейсе.