Функции с переменным числом параметров

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

static double CalcAverage(params double[] values)

{

double avarage = 0;

if (values.Length == 0) return 0;

foreach (double x in values)

avarage += x;

avarage /= values.Length;

return avarage;

}

static void Main(string[] args)

{

//1 способ

Console.WriteLine("Среднее арифметическое="+CalcAverage(0.2, 0.3, 0.5, 0.7));

//2 способ

double[] mas = { 0.2, 0.3, 0.5, 0.7 };

Console.WriteLine("Среднее арифметическое=" + CalcAverage(mas));

//3 способ

Console.WriteLine("Среднее арифметическое=" + CalcAverage());

}

 

 

Если бы в определении CalculateAverage () не было модификатора params, первый способ вызова этого метода приводил бы к ошибке на этапе компиляции, т.к. тогда компилятор искал бы версию CalculateAverage(), принимающую пять аргументов double.

Во избежание какой бы то ни было неоднозначности, в С# требуется, чтобы в любом методе поддерживался только один аргумент params, который должен быть последним в списке параметров.

Необязательные параметры

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

static void Print(string s = "номер дома", int value = 1)

{

Console.WriteLine(s + " " + value);

}

static void Main(string[] args)

{

 

Print();

Print("номер квартиры");

Print(,2);//Error!!!

Print("номер квартиры",15);

}

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

static void Print(double [] mas,int size=mas.Length)

{

// int size = mas.Length;

for (int i = 0; i < size; i++)

Console.Write(mas[i] + " ");

Console.WriteLine();

}

static void Main(string[] args)

{

double[] mas = { 0.2, 0.3, 0.5, 0.7 };

Print(mas);

}

Error – т.к. значение time вычисляется во время выполнения программы.

 

Именованные параметры

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

static void DisplayMessage(ConsoleColor textColor,ConsoleColor backgroundColor, string message)

{

// Сохранение старых цветов для обеспечения возможности

//их восстановления сразу после вывода сообщения.

ConsoleColor oldTextColor = Console.ForegroundColor;//свойство - возвращает цвет фона консоли, т.е. цвет символов

ConsoleColor oldbackgroundColor = Console.BackgroundColor;//свойство - возвращает цвет фона

// Установка новых цветов и вывод сообщения.

Console.ForegroundColor = textColor;

Console.BackgroundColor = backgroundColor;

Console.WriteLine(message);

// Восстановление предыдущих цветов.

Console.ForegroundColor = oldTextColor;

Console.BackgroundColor = oldbackgroundColor;

}

 

static void Main(string[] args)

{

 

DisplayMessage (message: "Печатаем сообщение ", textColor: ConsoleColor.DarkRed, backgroundColor: ConsoleColor.White);

DisplayMessage(backgroundColor: ConsoleColor.Green,message: "Меняем цвет...", textColor: ConsoleColor.DarkBlue);

Console.ReadLine();

 

// Здесь все в порядке, поскольку позиционные аргументы идут перед именованными.

DisplayMessage(ConsoleColor.Blue,message: "Testing...",backgroundColor: ConsoleColor.White);

// Здесь присутствует ошибка, поскольку позиционные аргументы идут после именованных.

DisplayMessage(message: "Testing...",backgroundColor: ConsoleColor.White, ConsoleColor.Blue);

}

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

static void DisplayMessage(ConsoleColor textColor = ConsoleColor.Blue,

ConsoleColor backgroundColor = ConsoleColor.White, string message = "Test Message")

{ . . . .}

DisplayMessage(backgroundColor: ConsoleColor.Green); //зеленый фон, синие буквы,

//Test Message

DisplayMessage(message:"Hello"); //белый фон, синие буквы, Hello

 

Перегрузка методов

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

static int MaxValue(int a, int b)

{

if (a > b)

return a;

else

return b;

}

static double MaxValue(double a, double b)

{

if (a > b)

return a;

else

return b;

}

static string MaxValue(string a, string b)

{

if (String.Compare(a,b)>0)

return a;

else

return b;

}

static void Main(string[] args)

{

Console.WriteLine("максимальное значение из {0} и {1} = {2}",1,5, MaxValue(1,5));

Console.WriteLine("максимальное значение из {0} и {1} = {2}", 1.5, 5.1, MaxValue(1.5, 5.1));

Console.WriteLine("максимальное значение из {0} и {1} = {2}", "111","555", MaxValue("111","555"));

}

}

Среда разработки Visual Studio 2010 обеспечивает помощь при вызове перегруженных методов. При вводе имени перегруженного метода (как, например, хорошо знакомого Console .WriteLine ()) в списке предлагаются все его доступные версии.

 

Рекурсия

Рекурсией называется ситуация, когда какой-то алгоритм вызывает себя прямо (прямая рекурсия) или через другие алгоритмы (косвенная рекурсия) в качестве вспомогательного. Сам алгоритм называется рекурсивным.

Рекурсивное решение задачи состоит из двух этапов:

1. исходная задача сводится к новой задаче, похожей на исходную, но несколько проще;

2. подобная замена продолжается до тех пор, пока задача не станет тривиальной, т. е. очень простой.

Задача 1. Вычислить факториал (n!), используя рекурсию.

Исходные данные: n

Результат: n!

Рассмотрим эту задачу на примере вычисления факториала для n=5. Более простой задачей является вычисление факториала для n=4. Тогда вычисление факториала для n=5 можно записать следующим образом:

5!=4!*5.

Аналогично:

4!=3!*4;

3!=2!*3;

2!=1!*2 ;

1!=0!*1

Тривиальная (простая) задача:

0!=1.

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

class Program

{

static int fact(int n)

{

if (n==0)return 1;//тривиальная задача

return (n*fact(n-1));

}

 

static void Main(string[] args)

{

Console.WriteLine("Введите число для вычисления факториала");

int k = Convert.ToInt32(Console.ReadLine());

Console.WriteLine("{0}!={1}",k,fact(k));

 

 

}

}

 

Задача 2. Вычислить степень, используя рекурсию.

Исходные данные: x,n

Результат: xn

Математическая модель:

 

static int pow(int x, int y)

{

if (y == 0) return 1;

else return (x * pow(x, y - 1));

}

 

static void Main(string[] args)

{

Console.WriteLine("Введите числа для вычисления степени");

int x = Convert.ToInt32(Console.ReadLine());

int y = Convert.ToInt32(Console.ReadLine());

Console.WriteLine("{0}^{1}={2}", x,y, pow(x,y));

}