среда, 25 августа 2010 г.

Основы C# - Часть 3

Работа со строками

Как мы уже могли убедиться в прошлой статье, тип данных string (строки Unicode) - это встроенный тип данных С#. Как и все встроенные типы данных, все строки в мире С# и .NET происходят от единственного базового класса – System.String. Этот базовый класс обеспечивает множество методов, которые призваны выполнить за вас всю черновую работу: возвратить количество символов в строке, найти подстроки, преобразовать все символы в строчные или прописные и т. д. Самые интересные, с нашей точки зрения, члены класса Sуstеm.String представлены в табл. 6:

Таблица 6. Методы класса System.String

Имя члена Назначение

Length Это свойство возвращает длину указанной строки

Concat() Этот статический метод класса String возвращает новую строку, «склеенную» из двух исходных

CompareTo() Сравнивает две строки

Copy() Этот Статический метод создает новую копию существующей строки

Format() Используется для форматирования строки с использованием других примитивов (числовых данных, других строк) и подстановочных выражений вида {0}

Insert() Используется для вставки строки внутрь существующей

PadLeft() PadRight() Эти методы позволяют заполнить (<<набить») строку указанными символами

Remove() Replace() Эти методы позволяют создать копию строки с внесенными изменениями (удаленными или замененными символами)

ToUpper() ToLower() Эти методы используются для получения копии строки, в которой все символы станут строчными или прописными

Обратите внимание на следующие моменты, связанные с работой со строковыми данными в С#. Во-первых, несмотря на то, что тип данных string - это ссылочный тип данных, при использовании операторов равенства (== и !=) происходит сравнение значений строковых объектов, а не адресов этих объектов в оперативной памяти. Во-вторых, оператор сложения (+) в С# перегружен таким образом, что при применении к строковым объектам он вызывает метод Concat().

Управляющие последовательности и вывод служебных символов

В С#, как и в С, и в С++, и в Java строки могут содержать любое количество управляющих последовательностей (escape characters):

Упр послед-сти Назначение

\’ Вставить одинарную кавычку в строку

\” Вставить двойную кавычку в строку

\\ Вставить в строку обратный слэш. Особенно полезно при работе с путями в файловой системе

\a Запустить системное оповещение (Alert)

\b Вернуться на одну позицию (Ваоорасе)

\f Начать следующую страницу (Form feed)

\n Вставить новую строку (New line)

\r Вставить возврат каретки (carriage Return)

\t Вставить горизонтальный символ табуляции (horizontal ТаЬ)

\u Вставить символ Unicode

\v Вставить вертикальный сиовол табуляции (Veгtical tab)

\0 Представляет пустой символ (NULL)

Помимо управляющих последовательностей, в С# предусмотрен также специальный префикс @ для дословного вывода строк вне зависимости от наличия в них управляющих последовательностей.

Применение System.Text.StringBuilder

При работе со строками в С# необходимо помнить очень важную вещь: значение строки не может быть изменено. Как и в Java, в С# строки являются неизменяемыми (immutable). System.Srting предоставляет в ваше распоряжение множество методов, однако эти методы только на первый взгляд могут изменять строки. На самом деле они возвращают лишь измененную копию строки.

Работа с копиями копий строк может в конце концов надоесть. Но С# предлагает еще одно средство, которое позволяет изменять строки напрямую, без создания лишних копий. Это средство - класс StringBuilder, определенный в пространстве имен System.Тext. Все изменения, которые вы вносите в объект этого класса, немедленно в нем отражаются, что во многих ситуациях гораздо эффективнее, чем работать с множеством копий.

using System;

using System.Text; // Здесь живет StringBuilder!

class StringApp

{

public static int Main(string[] args) {

// Создаем объект StringBuilder и изменяем его содержимое

StringBuilder myBuffer = new StringBuilder("I аm а buffer");

myBuffer.Append(" that just got longer...");

Console.WriteLine(myBuffer);

return 0;

}

}

Помимо добавления класс StringBuilder допускает и другие операции, например удаление определенных символов или их замену. После того как вы добились нужного вам результата, часто бывает удобным вызвать метод ToString(), чтобы перевести содержимое объекта StringBuilder в обычный тип данных String.

Перечисления С#

Часто бывает удобным создать набор значимых имен, которые будут представлять числовые значения. Представим себе, что вы создаете систему расчета заработной платы для сотрудников. Скорее всего, вам покажется более удобным вместо не­дружелюбных значений {О. 1. 2. З} использовать поНятные имена VP, Manager, Grunt и Contractor. Конечно же, С#, как и С/С++, предоставляет вам возможность использовать для этой цели перечисления (enumerations). Создание перечисле­ния для наших целей может выглядеть так:

// Создаем перечисление enum ЕmрТуре

{

Manager; //=0

Grunt; //=1

Contractor; //=2

VP; //=3

}

По необходимости можно изменить исходную точку отсчета и можно использовать не строго последовательные числовые значения.

Использование элементов перечисления: …EmpType.Contractor

Базовый класс System.Enum

Все перечисления в С# происходят от единого базового класса System.Enum. Конеч­но же, в этом базовом классе предусмотрены методы, которые могут существенно облегчить вашу работу с перечислениями.

Первый метод, о котором нео6ходимо упомянуть, - это статический метод GetUnderlyingType(), который позволяет получить информацию о том, какой тип данных используется для представления числовых значений элементов перечисления:

//Получаем тип числовых данных перечисления

Console.WriteLine(Enum, GetUnderlyingType(typebf(EmpType)));

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

В System.Enum предусмотрен еще один полезный статический метод – GetValues(). Этот метод возвращает экземпляр System.Array, при этом каждому элементу массива будет соответствовать член указанного перечисления

Аrrау obj = Enum.GetValues(typeof(EmpType));

Console.WriteLine("This enum has {О} members.". obj.Length);

Кроме того, в классе System.Еnum предусмотрено очень полезное свойство IsDefined. Оно позволяет определить, является ли выбранная вами символьная. строка элементом указанного перечисления. Например, предположим, что вам потребовалось узнать, является ли значение SalesPerson элементом перечисления ЕmрТуре:

Еmp. IsDefined(typeof(EmpType). "SalesPerson"));

Определение структур в С#

Во многих отношениях структуры С# можно рассматривать как некую особую разновидность классов. С классами структуры роднит многое: для структур можно определять конструкторы (только принимающие параметры), структуры могут реализовывать интерфейсы, структуры могут содержать любое количество внутренних членов. Для структур С# не существует единого базового класса (тип System.Structure в С# непредусмотрен), однако косвенно все структуры являются производными от типа ValueType. Вот простой пример структуры С#:

enum ЕmpType: byte

{ Manager = 10. Grunt = 1. Contractor = 100. VP = 9}

struct EMPLOYEE

{

// Одно из полей структуры – перечисление, определенное выше

public EmpType title;

public string name;

public short deptID;

}

Мы создали структуру EMPLOYEE (для нее была выделена память в области стека) и теперь можем обращаться к каждому члену структуры, используя формат имя-структуры. имя-члена. Вполне возможно, что в реальном приложении для более удобного присвоения значений членам структуры нам придется определить свой собственный конструктор или несколько конструкторов. В связи с этим необходимо помнить, что вы не можете переопределить конструктор для структуры по умолчанию - тот конструктор, который не принимает параметров. Все ваши конструкторы обязательно должны принимать один или несколько параметров:

public EMPLOYEE (ЕmpТуре et, string n, short d)

{title=et; name=n; deptID=d;}

Определяем пользовательские пространства имен

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

Предположим, что мы создаем набор геометрических классов. Один класс получит название Square (квадрат), второй - Circle (окружность), а третий - Hexagon (шестиугольник). Поскольку все эти классы относятся к геометрическим фигурам, мы принимаем решение сгруппировать их в общем пользовательском пространстве имен. Основных вариантов в нашем распоряжении два. Согласно первому, мы можем определить все классы в одном файле (shapeslib.cs). Согласно второму, мы можем разбить единое пространство имен С# на несколько физических файлов. Если вам потребуется использовать эти классы внутри другого приложения, удобнее всего это сделать при помощи ключевого слова using.

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

Небезопасный код

C# разрешает использовать указатели в специально помеченных блоках кода. Ключевое слово для этого – unsafe:

unsafe int Function(){

// работа с указателями

}

Небезопасным может быть объявлен любой метод – независимо от того, какие другие модификаторы были для него указаны.

Можно также пометить целый класс или структуру как uunsafe:

unsafe class MyClass{

// любой метод может работать с указателями

}

Можно также отметить блок внутри метода как unsafe:

unsafe{

// небезопасный код

}

Однако локальная переменная не может быть unsafe.

В блоках unsafe можно использовать операции sizeof, * , ->, &.

Синтаксис указателей

Сделав код небезопасным, можно объявить указатели, используя синтаксис:

int *pWidth, pHeight;

double ***pResult;

Необходимо обратить внимание на то, что в C# синтаксис отличается: оператор int *pWidth, pHeight; соответствует оператору C++ int *pWidth, *pHeight;.

Рассмотрим пример использования указателей:

using System;

class UnsafeTest

{

// unsafe method: takes pointer to int:

unsafe static void SquarePtrParam (int* p)

{

*p *= *p;

}

unsafe public static void Main()

{

int i = 5;

// unsafe method: uses address-of operator (&)

SquarePtrParam (&i);

Console.WriteLine (i);

}

}

Комментариев нет:

Отправить комментарий