Эндрю Троелсен - ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
очень
очень
длинная строка";
Console.WriteLine(myLongString);
Двойную кавычку в такой строковый литерал можно вставить с помощью дублирования знака ", например:
Console.WriteLine(@"Cerebus said ""Darrr! Pret-ty sun-sets""");
Роль System.Text.StringBuilder
Тип string прекрасно подходит для того, чтобы представлять базовые строковые переменные (имя, SSN и т.п.), но этого может оказаться недостаточно, если вы создаете программу, в которой активно используются текстовые данные. Причина кроется в одной очень важной особенности строк в .NET: значение строки после ее определения изменить нельзя. Строки в C# неизменяемы.
На первый взгляд, это кажется невероятным, поскольку мы привыкли присваивать новые значения строковым переменным. Однако, если проанализировать методы System.String, вы заметите, что методы, которые, как кажется, внутренне изменяют строку, на самом деле возвращают измененную копию оригинальной строки. Например, при вызове ToUpper() для строкового объекта вы не изменяете буфер существующего строкового объекта, а получаете новый строковый объект в форме символов верхнего регистра.
static void Main(string[] args) {
…
// Думаете, что изменяете strFixed? А вот и нет!
System.String strFixed = "Так я начинал свою жизнь";
Console.WriteLine(strFixed);
string upperVersion = strFixed.ToUpper();
Console.WriteLine(strFixed);
Console.WriteLine("{0}nn", upperVersion);
…
}
Подобным образом, присваивая существующему строковому объекту новое значение, вы фактически размещаете в процессе новую строку (оригинальный строковый объект в конечном итоге будет удален сборщиком мусора). Аналогичные действия выполняются и при конкатенации строк.
Чтобы уменьшить число копирований строк, в пространстве имен System.Text определяется класс StringBuilder (он уже упоминался нами выше при рассмотрении System.Object). В отличие от System.String, тип StringBuilder обеспечивает прямой доступ к буферу строки. Подобно System.String, тип StringBuilder предлагает множество членов, позволяющих добавлять, форматировать, вставлять и удалять данные (подробности вы найдете в документации .NET Framework 2.0 SDK).
При создании объекта StringBuilder можно указать (через аргумент конструктора) начальное число символов, которое может содержать объект. Если этого не сделать, то будет использоваться "стандартная емкость" StringBuilder, по умолчанию равная 16. Но в любом случае, если вы увеличите StringBuilder больше заданного числа символов, то размеры буфера будут переопределены динамически.
Вот пример использования этого типа класса.
using System;
using System.Text; // Здесь 'живет' StringBuilder.
class StringApp {
static void Main(string[] args) {
StringBuilder myBuffer = new StringBuilder("Моя строка");
Console.WriteLine("Емкость этого StringBuilder: {0}", myBuffer.Capacity);
myBuffer.Append(" содержит также числа:");
myBuffer.AppendFormat("{0}, {1}.", 44, 99);
Console.WriteLine("Емкость этого StringBuilder: {0}", myBuffer.Сарасitу);
Console.WriteLine(myBuffer);
}
}
Во многих случаях наиболее подходящим для вас текстовым объектом будет System.String. Для большинства приложений потери, связанные с возвращением измененных копий символьных данных, будут незначительными. Однако при построении приложений, интенсивно использующих текстовые данные (например, текстовых процессоров), вы, скорее всего, обнаружите, что использование System.Text.StringBuilder повышает производительность.
Исходный код. Проект Strings размешен в подкаталоге, соответствующем главе 3.
Типы массивов .NET
Формально говоря, массив - это коллекция указателей на данные одного и того же вполне определенного типа, доступ к которым осуществляется по числовому индексу. Массивы являются ссылочными типами и получаются из общего базового класса System.Array. По умолчанию для .NET-мaccивов начальный индекс равен нулю, но с помощью статического метода System.Array.CreateInstance() для любого массива можно задать любую нижнюю границу для его индексов.
Массивы в C# можно объявлять по-разному. Во-первых, если вы хотите создать массив, значения которого будут определены позже (возможно после ввода соответствующих данных пользователем), то, используя квадратные скобки ([]), укажите размеры массива во время его создания. Например:
// Создание массива строк, содержащего 3 элемента (0-2)
string[] booksOnCOM;
booksOnCOM = new string[3];
// Инициализация 100-элементного массива с нумерацией (0 - 99)
string[] booksOnDotNet = new string[100];
Объявив массив, вы можете использовать синтаксис индексатора, чтобы присвоить значения его элементам.
// Создание, заполнение и печать массива из трех строк.
string[] booksOnCOM; booksOnCOM = new string[3];
booksOnCOM[0] = "Developer's Workshop to COM and ATL 3.0";
booksOnCOM[1] = "Inside COM";
booksOnCOM[2] = "Inside ATL";
foreach (string s in booksOnCOM) Console.WriteLine(s);
Если значения массива во время его объявления известны, вы можете использовать "сокращенный" вариант объявления массива, просто указав эти значения в фигурных скобках. Указывать размер массива в этом случае не обязательно (он вычисляется динамически), как и при использовании ключевого слова new. Так, следующие варианты объявления массива эквивалентны.
// 'Краткий' вариант объявления массива
// (значения во время объявления должны быть известны).
int[] n = new int[] {20, 22, 23, 0};
int[] n3 = {20, 22, 23, 0};
И наконец, еще один вариант создания типа массива.
int[] n2 = new int[4] {20, 22, 23, 0}; // 4 элемента, {0 - 3}
В данном случае указанное числовое значение задает число элементов в массиве, а не граничное сверху значение для индексов. При несоответствии между объявленным размером и числом инициализируемых элементов вы получите сообщение об ошибке компиляции.
Независимо от того, как вы объявите массив, элементам в .NET-массиве автоматически будут присвоены значения, предусмотренные по умолчанию, сохраняющиеся до тех пор, пока вы укажете иные значения. Так, в случае массива числовых типов, каждому его элементу присваивается значение 0 (или 0.0 в случае чисел с плавающим разделителем), объектам присваивается null (пустое значение), а типам Boolean – значение false (ложь).
Массивы в качестве параметров (и возвращаемых значений)
После создания массива вы можете передавать его, как параметр, или получать его в виде возвращаемого значения. Например, следующий метод PrintArray() получает входной массив строк и выводит каждый элемент на консоль, а метод GetStringArray() "наполняет" массив значениями и возвращает его вызывающей стороне.
static void PrintArray(int[] myInts) {
for (int i = 0; i ‹ myInts.Length; i++) Console.WriteLine("Элемент {0} равен {1}", i, myInts[i]);
}
static string[] GetStringArray() {
string theStrings = { "Привет", "от", "GetStringArray"};
return theStrings;
}
Эти методы можно вызвать из метода Main(), как показано ниже.
static void Main(string[] args) {
int[] ages={20, 22, 23, 0};
PrintArray(ages);
string[] strs = GetStringArray();
foreach(string s in strs) Console.WriteLine(s);
Console.ReadLine();
}
Работа с многомерными массивами
Вдобавок к одномерным массивам, которые мы рассматривали до сих пор, в C# поддерживаются два варианта многомерных массивов. Первый из них – это прямоугольный массив, т.е. многомерный массив, в котором каждая строка оказывается одной и той же длины. Чтобы объявить и заполнить многомерный прямоугольный массив, действуйте так, как показано ниже.
static void Main(string[] args) {
…
// Прямоугольный массив MD .
int[,] myMatrix;
myMatrix = new int[6,6];
// Заполнение массива (6 * 6).
for (int i = 0; i ‹ 6; i++) for (int j = 0; j ‹ 6; j++) myMatrix[i, j] = i * j;
// Печать массива (6 * 6).
for (int i = 0; i ‹ 6; i++) {
for(int j = 0; j ‹ 6; j++) Console.Write(myMatrix[i, j] + "t");
Console.WriteLine();
}
…
}
На рис. 3.22 показан соответствующий вывод (обратите внимание на прямоугольный вид массива).
Рис. 3.22. Многомерный массив
Второй тип многомерных массивов – это невыровненный массив. Как следует из самого названия, такой массив содержит некоторый набор массивов, каждый из которых может иметь свой верхний предел для индексов. Например: