Г. Шилдт - Полный справочник по C# (1160789), страница 35
Текст из файла (страница 35)
Поскольку создается новый string-объект, содержащий подстроку, исходнаястрока остается неизменной, и правило постоянства строк не нарушается. Вот форматвызова метода Substring ():s t r i n g S u b s t r i n g ( i n t start,i n t len)Здесь параметр start означает индекс начала, а параметр len задает длину подстроки.Рассмотрим программу, которая демонстрирует метод Substring () и принциппостоянства строк.// Использование метода S u b s t r i n g ( ) .using System;c l a s s SubStr {p u b l i c s t a t i c void Main() {s t r i n g o r g s t r = "C# упрощает работу со строками.";// Создание подстроки.s t r i n g s u b s t r = o r g s t r .
S u b s t r i n g ( 4 , 14);Console.WriteLine("orgstr:Console.WriteLine("substr:" + orgstr);" + substr);А вот как выглядят результаты работы этой программы:o r g s t r : C# упрощает работу со строками,s u b s t r : прощает работуГлава 7. Массивы и строки177Как видите, исходная строка o r g s t r не изменена, а строка s u b s t r содержит нужную подстроку.И хотя постоянство string-объектов обычно не является ограничением, не исключены ситуации, когда возможность модифицировать строки могла бы оказатьсявесьма кстати.
Для таких случаев в С# предусмотрен класс S t r i n g B u i l d e r , которыйопределен в пространстве имен System.Text. Этот класс создает объекты, которыеможно изменять. Однако в большинстве случаев все же используются s t r i n g объекты, а не объекты класса S t r i n g B u i l d e r .Использование строк в switch-инструкцияхДля управления switch-инструкциями можно использовать string-объекты, причем это единственный тип, который там допускается, помимо типа i n t .
Эта возможность в некоторых случаях облегчает обработку. Например, следующая программаотображает цифровой эквивалент слов "один", "два" и "три".// Демонстрация возможности строкового управления// инструкцией switch.using System;class StringSwitch {public static void Main() {string[] strs = { "один", "два", "три", "два", "один" };foreach(string s in strs) {switch(s) {case "один":Console.Write(Inbreak;case "два":Console.Write(2);break;case "три":Console.Write ( 3 ) ;break;Console.WriteLine();Вот результат выполнения этой программы:12321178Часть I. Язык С#Полныйсправочник понее о методах и классахВэтой главе мы снова обращаемся к рассмотрению методов и классов.
Начнем суправления доступом к членам класса. Затем обсудим возможность передачиметодам объектов и их возврата, после чего рассмотрим перегрузку методов, различные формы метода Main (), рекурсию и использование ключевого слова s t a t i c .Управление доступом к членам классаПоддерживая инкапсуляцию, класс обеспечивает два положительных момента. Вопервых, он связывает данные с кодом (мы используем это преимущество начиная сглавы 6). Во-вторых, он предоставляет средства управления доступом к членам класса.На этом мы сейчас и остановимся.Хотя в действительности дело обстоит несколько сложнее, но по сути существуютдва базовых типа членов класса: открытые и закрытые. К открытому члену класса может свободно получить доступ код, определенный вне этого класса.
До сих пор мыкак раз и использовали члены такого типа. К закрытому же члену класса доступ могутполучить методы, определенные только в этом классе. Благодаря использованию закрытых членов класса мы и имеем возможность управлять доступом.Ограничение доступа к членам класса — это фундаментальная часть объектноориентированного программирования, поскольку она предотвращает неверное использование объекта.
Разрешая доступ к закрытым данным только посредством строгоопределенного набора методов, вы имеете возможность не допустить присвоение этимданным неподходящих значений, выполнив, например, проверку диапазона. Код, непринадлежащий классу, не может устанавливать закрытые члены напрямую. И именно программист управляет тем, как и когда будут использоваться данные объекта. Таким образом, при корректной реализации класс создает "черный ящик", с которымможно работать, но внутреннее функционирование которого закрыто для вмешательства извне.Спецификаторы доступа С#Управление доступом к членам класса достигается за счет использования четырехспецификаторов доступа: p u b l i c , p r i v a t e , p r o t e c t e d и i n t e r n a l . В этой главе мыограничимся рассмотрением спецификаторов p u b l i c и p r i v a t e .
Модификаторp r o t e c t e d применяется только при включении интерфейсов и описан в главе 9. Модификатор i n t e r n a l применяется в основном при использовании компоновочныхфайлов (assembly) и описан в главе 16.Спецификатор p u b l i c разрешает доступ к соответствующему члену класса со стороны другого кода программы, включая методы, определенные внутри других классов.Спецификатор p r i v a t e разрешает доступ к соответствующему члену класса толькодля методов, определенных внутри того же класса.
Таким образом, методы другихклассов не могут получить доступ к private-члену не их класса. Как разъяснялось вглаве 6, при отсутствии спецификатора доступа член класса является закрытым( p r i v a t e ) по умолчанию. Следовательно, при создании закрытых членов класса спецификатор p r i v a t e необязателен.Спецификатор доступа должен стоять первым в списке спецификаторов типа любого члена класса.
Вот несколько примеров:public string errMsg;private double bal;private bool isError(byte status) { // ...I180Часть I. Язык C#Чтобы лучше понять разницу между спецификаторами public и private, рассмотрим следующую программу:// Сравнение доступа к открытым и закрытым членам класса.using System;class MyClass {private int alpha; // Явно задан спецификатор private,int beta;// Спецификатор private по умолчанию,public int gamma; // Явно задан спецификатор public./* Методы для получения доступа к членам alpha и beta.Другие члены класса беспрепятственно получают доступк private-члену того же класса.*/public void setAlpha(int a) {alpha = а;}»public int getAlpha() {return alpha;}public void setBeta(int a) {beta = a;public int getBetaO {return beta;class AccessDemo {public s t a t i c void Main() {MyClass ob = new MyClass();/* Доступ к private-членам alpha и beta разрешентолько посредством соответствующих методов.
*/ob.setAlpha(-99);ob.setBeta(19);Console.WriteLine("Член ob.alpha равен " +ob.getAlpha());Console.WriteLine("Член ob.beta равен " +ob. getBetaO ) ;////// К private-членам alpha или beta нельзя получить// доступ таким образом:ob.alpha = 10; // Неверно! alpha -- закрытый член!ob.beta = 9 ;// Неверно! beta -- закрытый член!// Можно получить прямой доступ/ / к члену gamma, поскольку он открытый член.ob.gamma = 99;Как видите, внутри класса MyClass член alpha явно определен как private-член,beta — private-член по умолчанию, a gamma определен как public-член. ПосколькуГлава 8. Подробнее о методах и классах181alpha и b e t a — закрытые члены, к ним нельзя получить доступ не из их "родного"класса.
Следовательно, внутри класса AccessDemo к этим членам нельзя обратитьсянапрямую. К каждому из них необходимо обращаться только через открытые(public-) методы, например setAlphaO или getAlpha(). Если удалить символкомментария в начале строки1 // ob.alpha = 10; // Неверно! alpha -- закрытый ч л е н ! ,то вы бы не смогли скомпилировать эту программу по причине нарушения доступа кзакрытому члену класса.
Несмотря на то что доступ к члену alpha вне классаMyClass не разрешен, методы, определенные в классе MyClass (setAlphaO иgetAlpha ()), могут к нему обращаться. Это справедливо и для члена b e t a .Итак, к закрытым членам могут свободно обращаться другие члены того же класса,но не методы, определенные вне этого класса.Применение спецификаторов доступа p u b l i c и p r i v a t eНадлежащее использование спецификаторов доступа p u b l i c и p r i v a t e —- залогуспеха объектно-ориентированного программирования.
Хотя на этот счет не существует жестких правил, все же программисты выработали общие принципы, которымиследует руководствоваться при программировании классов.1. Члены, которые используются только внутри класса, следует определить какзакрытые.2. Данные экземпляров, которые должны находиться в пределах заданного диапазона, следует определить как закрытые, а доступ к ним обеспечить через открытые методы, выполняющие проверку вхождения в диапазон.3. Если изменение члена может вызвать эффект, распространяющийся за пределы самого члена (т.е. действует на другие аспекты объекта), этот член следуетопределить как закрытый и обеспечить к нему контролируемый доступ.4. Члены, при некорректном использовании которых на объект может быть оказано негативное воздействие, следует определить как закрытые, а доступ к нимобеспечить через открытые методы, предохраняющие эти члены от некорректного использования.5. Методы, которые получают или устанавливают значения закрытых данных,должны быть открытыми.6.
Объявление переменных экземпляров открытыми допустимо, если нет причинделать их закрытыми.Безусловно, существует множество нюансов, не охваченных перечисленными вышепринципами. Кроме того, в некоторых случаях одно или несколько правил приходиться нарушать, но чаще всего соблюдение этих принципов позволяет создать объекты с высоким "иммунитетом" к некорректному использованию.Управление доступом: учебный проектУчебный проект поможет вам глубже понять управление доступом к членам класса.
Один из распространенных примеров объектно-ориентированного программирования — класс, реализуемый в стеке. (Стек — это структура данных, которая реализует список элементов по принципу: первым вошел — последним вышел. В качествебытового примера стека можно привести стопку тарелок, из которых первая поставленная на стол тарелка, будет использована последней.)182Часть I. Язык С#Стек — это классический пример объектно-ориентированного программирования,в котором сочетаются как средства хранения информации, так и методы получениядоступа к этой информации. Для реализации этого наилучшим образом подходиткласс, в котором члены, обеспечивающие хранение данных стека, являются закрытыми, а доступ к ним осуществляется посредством открытых методов.В стеке необходимо выполнить две операции: поместить данные в стек и извлечьих оттуда.
Каждое значение помещается в вершину стека и извлекается также из еговершины. Извлеченное из стека значение удаляется и не может быть извлечено снова.В приведенном ниже примере создается класс Stack, который реализует работустека. Хранение данных стека обеспечивается на основе закрытого массива. Операциипомещения данных в стек и извлечения их из него доступны через открытые методыкласса s t a c k . Таким образом, механизм "первым вошел — последним вышел" обеспечивается открытыми методами. В нашем примере класс s t a c k предназначен дляхранения символов, но аналогичный механизм можно использовать для храненияданных любого другого типа.// Класс стека для хранения символов.using System;class Stack {// Эти члены закрытые.char[] stck; // Массив для хранения данных стека.int tos;// Индекс вершины стека.// Создаем пустой класс Stack заданного размера,public Stack(int size) {stck = new char[size]; // Выделяем память для стека.tos = 0;}// Помещаем символы в стек.public void push(char ch) {if(tos==stck.Length) {Console.WriteLine(" - Стек заполнен.");return;stck[tos] = ch;tos++;// Извлекаем символ из стека,public char pop() {if(tos==0) {Console.WriteLine(" - Стек пуст.");return (char) 0;tos—;return stck[tos];// Метод возвращает значение true, если стек полон,public bool full() {return tos==stck.Length;Глава 8.