Параметры функции
Основным способом обмена информацией между вызываемой и вызывающей функциями является механизм параметров.
При определении метода в его заголовке размещается спецификация параметров, она может быть пустой. Спецификация параметров – последовательность описаний параметров:
модификатор тип_параметра имя_параметра
Модификатор может отсутствовать или иметь одну из следующих форм: ref, out, params.
Параметр может быть любого типа (базового, строкой, object, массив, перечисление и т.д.).
Имя параметра – идентификатор, выбираемый программистом. Область видимости и время действия параметра – заголовок и тело функции. Т.е. вне кода функции параметры не определены и недоступны.
Существуют следующие способы передачи параметров в функцию:
1. по значению;
2. по ссылке (ref);
3. выходные параметры (out);
4. массив-параметр (params).
При передаче по значению выполняются следующие действия:
1) вычисляются значения выражений, стоящие на месте фактических параметров;
2) в стеке выделяется память под формальные параметры функции;
3) каждому фактическому параметру присваивается значение формального параметра, при этом проверяются соответствия типов и при необходимости выполняются их преобразования.
Пример1.
static double square(double a, double b, double c)
{
double s, p=(a+b+c)/2;
return s = Math.Sqrt(p * (p - a) * (p - b) * (p - c));//формула Герона
}
Пример2.
class Program
{
public static void Change(int a, int b)
{
int r = a;
a = b;
b = r;
}
static void Main(string[] args)
{
int x = 10, y = 5;
Console.WriteLine("x=" + x + " y=" + y);
Change(x,y);
Console.WriteLine("x=" +x + " y=" + y);
}
Таким образом, при передаче параметров по значению в стек заносятся копии фактических параметров, и операторы функции работают с этими копиями. Доступа к самим фактическим параметрам у функции нет, следовательно, нет возможности их изменить.
Чтобы метод мог с помощью параметров изменять внешние по отношению к методу объекты, параметры должны иметь модификатор ref, т.е. передаваться по ссылке.
class Program
{
public static void Change(ref int a, ref int b)
{
int r = a;
a = b;
b = r;
}
static void Main(string[] args)
{
int x = new int(), y = new int();
x = 5; y = 10;
Console.WriteLine("x=" + x + " y=" + y);
Change(ref x, ref y);
Console.WriteLine("x=" + x + " y=" + y);
}
Параметры, передаваемые по ссылке, используются для изменения уже существующих значений, внешних по отношению к методу объектов.
Выходные параметры снабжаются модификатором out и позволяют присвоить значения объектам вызывающего метода даже в тех случаях, когда эти объекты значений еще не имели. Локальным переменным, передаваемым в качестве выходных параметров, присваивать начальные значения не требуется (после вызова эти значения все равно будут утрачены). Причина, по которой компилятор позволяет передавать на первый взгляд неинициализированные данные, связана с тем, что в вызываемом методе операция присваивания должна выполняться обязательно.
static void fun(double x, out int integer, out double fraction)
{
integer=(int)x;
fraction=x-integer;
}
static void Main(string[] args)
{
double number = 1.23456;
int iPart;
double dPart;
//integer и fraction не инициализируются до вызова функции
fun(number,out iPart,out dPart);
Console.WriteLine("Целая часть {0}, вещественная часть{1}",iPart,dPart);
}
Метод с выходными параметрами (имеющими модификаторы ref или out) обычно выступает в роли процедуры. Хотя не запрещено такому методу возвращать значение с помощью оператора return.
Отличия между ссылочными и выходными параметрами.
• Выходные параметры не нужно инициализировать перед передачей методу, т.к. метод сам должен присваивать значения выходным параметрам перед выходом.
• Ссылочные параметры нужно обязательно инициализировать перед передачей методу, т.к. они подразумевают передачу ссылки на уже существующую переменную. Если первоначальное значение ей не присвоено, это будет равнозначно выполнению операции над неинициализированной локальной переменной.