}
Как вы и должны ожидать, значения х и у остаются теми же и после вызова Add().
Модификатор out
Теперь рассмотрим использование параметров out (от output – выходной). Если метод определен с выходными параметрами, то необходимо назначить этим параметрам подходящие значения до выхода из метода (если этого не сделать, будет сгенерирована ошибка компиляции).
Ниже для иллюстрации предлагается альтернативный вариант метода Add(), использующий C#-модификатор out и возвращающий сумму двух целых чисел в виде выходного параметра (обратите внимание на то, что возвращаемым значением самого метода теперь будет void).
// Выходные параметры задаются членом.
public static void Add(int x, int y, out int ans) {
ans = x + y;
}
При вызове метода с выходными параметрами тоже требуется указать модификатор out. Локальным переменным, используемым в качестве выходного параметра, не требуется присваивать значения до их использования (эти значения после вызова все равно будут потеряны), Например:
static void Main(string[] args) {
// Нет необходимости задавать значения
// локальным выходным переменным.
int ans;
Add(90, 90, out ans);
Console.WriteLine("90 + 90 = {0} ", ans);
}
Этот пример предлагается здесь только для иллюстрации: нет никакой необходимости возвращать значение суммы с помощью выходного параметра. Но сам модификатор out играет очень важную роль: он позволяет вызывающей стороне получить множество возвращаемых значений от одного вызова метода.
// Возвращение множества выходных параметров.
public static void FillTheseVals(out int a, out string b, out bool c) {
а = 9;
b = "Радуйтесь своей строке.";
с = true;
}
Вызывающая сторона может вызвать этот метод следующим образом.
static void Main(string[] args) {
int i; string str; bool b;
FillTheseVals(out i, out str, out b);
Console.WriteLine("Int равно: {0}", i);
Console.WriteLine("String равно: (0}", str);
Console.WriteLine("Boolean равно: {0}", b);
}
Модификатор ref
Теперь рассмотрим, использование в C# модификатора ref (от reference – ссылочный). Ссылочные параметры нужны тогда, когда требуется позволить методу изменять данные, объявленные в контексте вызова (например, в функциях сортировки или обмена данными). Обратите внимание на различие между выходными и ссылочными параметрами.
• Выходные параметры не требуется инициализировать перед передачей их методу. Причина в том, что сам метод должен присвоить значения выходным параметрам.
• Ссылочные параметры необходимо инициализировать до того, как они будут переданы методу. Причина в том, что передается ссылка на существующую переменную. Если не присвоить переменной начальное значение, это будет означать использование неинициализированной переменной.
Давайте продемонстрируем использование ключевого слова ref с помощью метода, в котором осуществляется обмен значениями двух строк.
// Ссылочные параметры.
public static void SwapStrings(ref string s1, ref string s2) {
string tempStr = s1;
s1 = s2;
s2 = tempStr;
}
Этот метод можно вызвать так.
static void Main(string[] args) {
string s = "Первая строка";
string s2 = "Вторая строка";
Console.WriteLine("До: {0}, {1} ", s, s2);
SwapStrings(ref s, ref s2);
Console.WriteLine("После: {0}, {1} ", s, s2);
}
Здесь вызывающая сторона присваивает начальное значение локальным строковым данным (s и s2). По завершении вызова SwapStrings() строка s содержит значение "Вторая строка", a s2 – значение "Первая строка".
Модификатор params
Нам осталось рассмотреть модификатор params, позволяющий создавать методы, которым можно направить множество однотипных аргументов в виде одного параметра. Чтобы прояснить суть дела, рассмотрим метод, возвращающий среднее для любого числа значений,
// Возвращение среднего для 'некоторого числа' значений.
static double CalculateAverage(params double[] values) {
double sum = 0;
for (int i = 0; i ‹ values.Length; i++) sum += values[i];
return (sum / values.Length);
}
Этот метод принимает массив параметров, состоящий из значений с двойной точностью. Метод фактически говорит следующее: "Дайте мне любой набор значений с двойной точностью, и я вычислю для них среднюю величину". Зная это, вы можете вызвать CalculateAverage() одним из следующих способов (если не использовать модификатор params в определении CalculateAverage(), то первый из указанных ниже вариантов вызова этого метода должен привести к ошибке компиляции).
static void Main(string[] args) {
// Передача в виде списка значений, разделенных запятыми,.…
double average;
average = CalculateAverage(4.0, 3.2, 5.7);
Console.WriteLine("Среднее 4.0, 3.2, 5.7 равно: {0}", average);
//… или передача в виде массива значений.
double[] data = {4.0, 3.2, 5.7};
average = CalculateAverage(data);
Console.WriteLine ("Среднее равно: {0}", average);
Console.ReadLine();
}
Это завершает наше вводное обсуждение модификаторов параметров. Мы снова обратимся к этой теме немного позже (в этой же главе), когда будем обсуждать различия между типами значений и ссылочными типами. А пока что давайте рассмотрим итерационные и условные конструкции языка программирования C#.
Исходный код. Проект SimpleParams размещен в подкаталоге, соответствующем главе 3.
Итерационные конструкции
Все языки программирования предлагают конструкции обеспечивающие возможность повторения блоков программного кода, пока не выполнено условие завершения повторений. Если у вас есть опыт программирования, то операторы цикла в C# будут для вас понятными и не должны требовать пространных объяснений.
В C# обеспечиваются следующие четыре итерационные конструкции:
• цикл for;
• цикл foreach/in;
• цикл while;
• цикл do/while.
Давайте рассмотрим все указанные конструкции по очереди.
Цикл for
Когда требуется повторить блок программного кода определенное число раз, оператор for подходит для этого лучше всего. Вы можете указать, сколько раз должен повториться блок программного кода, а также условие окончания цикла. Без лишних объяснений, вот вам соответствующий образец синтаксиса.
// База для цикла.
static void Main(string[] args) {
// Переменная 'i' доступна только в контексте этого цикла for.
for(int i = 0; i ‹ 10; i++) {
Console.WriteLine("Значение переменной: {0} ", i);
}
// Здесь переменная 'i' недоступна.
}
Все ваши привычные приемы использования циклов C, C++ и Java применимы и при построении операторов for в C#. Вы можете создавать сложные условия окончания цикла, строить бесконечные циклы, а также использовать ключевые слова goto, continue и break. Я думаю, что эта итерационная конструкция будет вам понятна. Если же вам требуются дальнейшие объяснения по поводу ключевого слова fоr в C#, используйте документацию .NET Framework 2.0 SDK.
Цикл foreach
Ключевое слово C# foreach позволяет повторить определенные действия для всех элементов массива без необходимости выяснения размеров массива. Вот два примера использования foreach, один для массива строк, а другой – для массива целых, чисел.
// Прохождение массива с помощью foreach.
static void Main(string[] args) {
string[] books = {"Сложные алгоритмы", "Классическая технология COM", "Язык C# и платформа .NET"};
foreach(string s in books) Console.WriteLine(s);
int[] myInts = {10, 20, 30, 40};
foreach(int i in myInts) Console.Writeline(i);
}
В дополнение к случаю простых массивов, foreach можно использовать и для просмотра системных и пользовательских коллекций. Обсуждение соответствующих подробностей предполагается в главе 7, поскольку этот вариант применения ключевого слова foreach предполагает понимание интерфейсного программирования и роли интерфейсов IEnumerator и IEnumerable.
Конструкции while и do/while
Цикл while оказывается полезным тогда, когда блок операторов должен выполняться до тех пор, пока не будет достигнуто заданное условие. Конечно, при этом требуется, чтобы в области видимости цикла while было определено условие окончания цикла, иначе вы получите бесконечный цикл. В следующем примере сообщение "в цикле while" будет печататься до тех пор, пока пользователь не введет значение "да" в командной строке.