Свойства, доступные только для чтения и только для записи 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Свойства, доступные только для чтения и только для записи



Существует возможность создать свойство, доступное только для чтения, просто исклю­чая set из определения свойства. То есть, чтобы сделать свойство Name из предыдущего примера доступным только для чтения, необходимо поступить следующим образом:

private string name;

public string Name

{

get

{

return name;

}

}

Точно так же можно определить свойство, доступное только для записи, если исклю­чить определение get. Однако это считается плохой практикой программирования, по­скольку может ввести в заблуждение авторов клиентского кода. Вообще говоря, если воз­никает искушение поступить так, то лучше вместо свойства использовать метод.

Модификаторы доступа для свойств

Язык С# допускает применение различных модификаторов доступа для средств set и get свойств. Это дает возможность свойству иметь общедоступный get и приватный или защищенный set, и управлять тем, как и когда свойство может быть установлено. В сле­дующем примере кода обратите внимание, что set имеет модификатор приватного дос­тупа (private), a get - не имеет никакого. В этом случае get получает уровень доступа самого свойства. Одно из средств доступа - set или get - должно иметь уровень доступа свойства. Если get также будет иметь ассоциированный с ним защищенный уровень дос­тупа, то компилятор сгенерирует ошибку, поскольку в этом случае и set, и get получают уровень доступа, отличающийся от уровня доступа самого свойства.

public string Mame

{

get

{

return _name;

}

private set

{

_name = value;

}

}

Автоматически реализуемые свойства

Если наличие какой-либо логики в методах set и get свойства не предполагается, мож­но использовать автоматически реализуемые свойства. Такие свойства создают поддержи­вающие их переменные-члены автоматически. Код ранее приведенного примера с Age вы­глядел бы следующим образом:

public int Age (get; set;}

В объявлении private int age; нет необходимости — компилятор создаст его авто­матически.

При использовании автоматически реализуемых свойств проверка достоверности свой­ства не может быть выполнена в его методе set. Поэтому в предыдущем примере мы бы не смогли проверить корректность установки возраста. Также должны присутствовать оба метода доступа. То есть, попытка сделать свойство доступным только для чтения вызовет ошибку:

public int Age (get;)

Однако уровень доступа каждого метода доступа может быть различным. Поэтому сле­дующий код является допустимым:

public int Age (get; private set; }

 

Замечание о встраивании

Некоторые разработчики могут быть обеспокоены тем, что в предыдущих разделах де­монстрируется множество ситуаций, когда стандартная практика кодирования С# порож­дает множество очень маленьких функций - например, для доступа к полю через свойство вместо непосредственного обращения к нему. Не повлияет ли это на производительность из-за накладных расходов, связанных с дополнительными вызовами функций? Ответ со­стоит в том, что не нужно беспокоиться о потере производительности по причине такой методологии программирования на С#. Вспомните, что код С# транслируется в IL, а затем JIT компилирует его во время выполнения в родной исполняемый код. JIT-компилятор спроектирован так, что генерирует высоко оптимизированный код и без колебаний ис­пользует встроенный (inline) код там, где это необходимо (т.е. заменяет вызовы функций встроенным кодом). Метод или свойство, чья реализация просто вызывает другой метод или возвращает поле, почти наверняка будет преобразован во встроенный код. Однако следует отметить, что решение относительно встраивания принимает исключительно CLR. У вас нет никакой возможности управлять тем, какие методы будут встроенными - например, с помощью какого-то ключевого слова вроде применяемого в С++ inline.

Конструкторы

Синтаксис объявления базовых конструкторов выглядит как объявление метода, кото­рый имеет то же имя, что и включающий его класс, и не имеет никакого типа возврата:

public class MyClass i

{

public MyClass ()

{

}

// остаток определения класса

Предусматривать конструктор в классе не обязательно. И до сих пор это не делалось ни в одном из приведенных примеров. В общем случае, если никакого конструктора не оп­ределяется, то компилятор просто создаст конструктор по умолчанию "за кулисами". Это будет конструктор очень обобщенного вида, который просто инициализирует все поля-ч­лены, обнуляя их (null-ссылки для ссылочных типов, 0 для числовых типов и false - для булевских). Часто это вполне адекватно; если же нет, то придется написать свой собствен­ный конструктор.

Конструкторы подчиняются тем же правилам перегрузки, что и обычные методы (т.е.
можно определять столько перегрузок конструктора, сколько необходимо, при условии,
что они будут отличаться сигнатурой):

public MyClass () // конструктор без параметров

{

//код конструктора

}

public MyClass(int number) // другая перегрузка

{

//код конструктора

}

Однако обратите внимание, что если вы применяете любой конструктор с парамет­рами, то в этом случае компилятор не генерирует никакого конструктора по умолчанию. Такой конструктор генерируется только тогда, когда ни одного конструктора явно не оп­ределено. В следующем примере, поскольку определен конструктор с одним параметром, компилятор предполагает, что это - единственный конструктор, который вы хотите сде­лать доступным, а потому не применяет никакого другого:

public class MyNumber

{

private int number;

public MyNumber(int number)

{

this.number = number;

}

}

Этот код также иллюстрирует типичное использование ключевого слова this для того, чтобы отличать поля класса от параметров с теми же именами. Теперь, если попытаться создать экземпляр класса MyNumber с помощью конструктора без параметров, возникнет ошибка компиляции:

MyNumber numb = new MyNumber (); //вызовет ошибку при компиляции

Следует упомянуть также, что конструкторы можно объявлять приватными или защи­щенными - так, что они будут невидимыми коду других классов:

public class MyNumber

{

private int number;

private MyNumber(int number) // другая перегрузка

{

this.number = number;

}

}

Этот пример на самом деле не определяет никакого общедоступного или даже защи­щенного конструктора для MyNumber. Это делает невозможным создание экземпляра дан­ного класса внешним кодом с помощью операции new (хотя можно написать общедоступ­ное статическое свойство или метод, в котором будет создаваться экземпляр класса). Это удобно в двух ситуациях:

1) если класс служит лишь контейнером для некоторых статических членов или свойств, а потому его экземпляры никогда не создаются;

2) если необходимо, чтобы экземпляры класса создавались только вызовом некоторой статической функции-члена (так называемый подход "фабрик классов" к созданию объектов).

Статические конструкторы

Одним из новых средств С# является возможность написания статических конструк­торов класса без параметров. Такой конструктор выполняется лишь однажды, в противо­положность всем описанным до сих пор конструкторам, которые были конструкторами экземпляров и выполнялись при каждом создании объектов классов.

class MyClass

{

static MyClass ()

{

// код инициализации

}

// остаток определения класса

}

Одной из причин для написания статического конструктора может быть наличие в классе некоторых статических полей или свойств, которые должны быть инициализиро­ваны внешним источником, прежде чем класс будет использован впервые.

Исполняющая среда.NET не дает никаких гарантий того, что статический конструктор будет вызван, поэтому в него не следует помещать код, который должен быть выполнен в определенный момент (например, при загрузке сборки в память). Точно так же невозмож­но предсказать, в каком порядке будут выполнены статические конструкторы различных классов.

Единственное, что гарантируется - это то, что статический конструктор будет запущен максимум один раз и что он будет вызван до любого первого обращения к данному классу. В С# статический конструктор обычно выполняется непосредственно перед первым вызо­вом любого члена класса.

Обратите внимание, что статический конструктор не имеет никакого модификатора дос­тупа. Он никогда не вызывается никаким другим кодом С#, а всегда только исполняющей средой.NET при загрузке класса, поэтому никакой модификатор доступа вроде public или private не имеет смысла. По той же причине статический конструктор не может прини­мать никаких параметров, и у каждого класса может быть только один статический конст­руктор. Должно быть очевидным также, что статический конструктор может иметь доступ только к статическим членам класса, но не членам экземпляра.

Также следует отметить, что в классе допускается определять одновременно статиче­ский конструктор и конструктор экземпляра без параметров. Хотя их списки параметров идентичны, не возникает никакого конфликта, потому что статический конструктор вы­полняется во время загрузки класса, а конструктор экземпляра - при создании экземпляра, поэтому не происходит никакой путаницы с тем, когда какой конструктор вызывать.

Кроме того, если есть более одного класса со статическим конструктором, то неиз­вестно, какой из статических конструкторов будет вызван первым. Поэтому в статический конструктор не должен помещаться код, который бы зависел от того, были или не были вызваны ранее другие статические конструкторы. С другой стороны, если любые статиче­ские поля должны иметь определенные значения по умолчанию, то они будут размещены, до вызова статического конструктора.

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

namespace Wrox.ProCSharp.StaticConstructorSample

{

public class UserPreferences

{

public static readonly Color BackColor;

static UserPreferences ()

{

DateTime now = DateTime.Now;

if (now.DayOfWeek == DayOfWeek.Saturday ||

now.DayOfWeek == DayOfWeek.Sunday)

BackColor = Color.Green;

else

BackColor = Color.Red;

}

private UserPreferences ()

{

}

}

}

Приведенный код демонстрирует, как предпочтительный цвет сохраняется в статиче­ской переменной, которая инициализируется статическим конструктором. Это поле объ­явлено как доступное только для чтения, т.е. его значение может быть установлено только в конструкторе. Далее в этой главе вы узнаете подробнее о полях, доступных только для чтения. Код использует ряд удобных структур, которые поставляются Microsoft как часть библиотеки классов.NET - System.DateTime и System.Drawing.Color.DateTime.

В Color.DateTime реализовано статическое свойство Now, возвращающее текущее вре­мя, и свойство экземпляра DayOfWeek, которое определяет, на какой день недели приходит­ся дата и время. Структура Color применяется для хранения цветов. Здесь реализованы также различные статические свойства, наподобие Red и Green, кото­рые, как показано в этом примере, возвращают часто используемые цвета. Чтобы исполь­зовать Color, во время компиляции необходимо сослаться на сборку System.Drawing.dll и добавить оператор using для пространства имен System.Drawing:

using System;

using System.Drawing;

Статический конструктор можно протестировать с помощью следующего кода:

class MainEntryPoint

{

static void Main(string[] args)

{

Console.WriteLine("Предпочтение пользователя: BackColor равно: "

+ UserPreferences.BackColor.ToString());

}

}

Компиляция и запуск этого кода даст следующий вывод:

Предпочтение пользователя: BackColor равно: Color [Red]

Конечно, если код выполняется в конце недели, предпочитаемым цветом может быть Green.



Поделиться:


Последнее изменение этой страницы: 2016-12-27; просмотров: 604; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.133.109.211 (0.079 с.)