При передаче параметров по ссылке перед параметрами используется модификатор ref:
static void Main(string[] args)
{
int x = 10;
int y = 15;
Addition(ref x, y); // вызов метода
Console.WriteLine(x);
Console.ReadLine();
}
// определение метода
static void Addition(ref int x, int y)
{
x += y;
}
В чем отличие двух способов передачи параметров? При передаче по значению метод получает не саму переменную, а ее копию. А при передаче параметра по ссылке метод получает адрес переменной в памяти. И, таким образом, если в методе изменяется значение параметра, передаваемого по ссылке, то также изменяется и значение переменной, которая передается на его место. Например:
static void Main(string[] args)
{
//Начальные значения переменных a и b
int a = 5;
int b = 6;
Console.WriteLine("Начальное значение переменной a = {0}", a);
//Передача переменных по значению
//После выполнения этого кода по-прежнему a = 5, так как мы передали лишь ее копию
AdditionVal(a, b);
Console.WriteLine("Переменная a после передачи по значению равна = {0}", a);
//Передача переменных по ссылке
//После выполнения этого кода a = 11, так как мы передали саму переменную
AdditionRef(ref a, b);
Console.WriteLine("Переменная a после передачи ссылке по значению равна = {0}", a);
Console.ReadLine();
}
// передача по ссылке
static void AdditionRef(ref int x, int y)
{
x = x + y;
Console.WriteLine("x + y = {0}", x);
}
// передача по значению
static void AdditionVal(int x, int y)
{
x = x + y;
Console.WriteLine("x + y = {0}", x);
}
Здесь в методе Main у нас есть две переменные: a и b. Имеется два метода, которые принимают два параметра: x и y. В обоих методах значение параметра x приравнивается сумме x и y.
В методе Main мы подставляем на место параметров x и y переменные a и b соответственно. В первом случае переменная передается по значению, то есть передается копия этой переменной, и она не изменяется. Во втором случае мы передаем указатель на эту переменную в памяти. И так как в методе AdditionRef значение параметра x изменяется, то передаваемая на его место переменная a тоже изменяет свое значение.
Обратите внимание, что модификатор ref указывается, как при объявлении метода, так и при его вызове в методе Main.
Модификатор out
Выше мы использовали входные параметры. Но параметры могут быть также выходными. Чтобы сделать параметр выходным, перед ним ставится модификатор out:
static void Sum(int x, int y, out int a)
{
a = x + y;
}
Здесь результат возвращается не через оператор return, а через выходной параметр. Использование в программе:
static void Main(string[] args)
{
int x = 10;
int z;
Sum(x, 15, out z);
Console.WriteLine(z);
Console.ReadLine();
}
Причем, как и в случае с ref ключевое слово out используется как при определении метода, так и при его вызове.
Также обратите внимание, что методы, использующие такие параметры, обязательно должны присваивать им определенное значение. То есть следующий код будет недопустим, так как в нем для out-параметра не указано никакого значения:
static void Sum(int x, int y, out int a)
{
Console.WriteLine(x+y);
}
Прелесть использования подобных параметров состоит в том, что по сути мы можем вернуть из метода не один вариант, а несколько. Например:
static void Main(string[] args)
{
int x = 10;
int area;
int perimetr;
GetData(x, 15, out area, out perimetr);
Console.WriteLine("Площадь: " + area);
Console.WriteLine("Периметр: " + perimetr);
Console.ReadLine();
}
static void GetData(int x, int y, out int area, out int perim)
{
area= x * y;
perim= (x + y)*2;
}
Здесь у нас есть метод GetData, который, допустим, принимает стороны прямоугольника. А два выходных параметра мы используем для подсчета площади и периметра прямоугольника.
По сути, как и в случае с ключевым словом ref, ключевое слово out применяется для для передачи аргументов по ссылке. Однако в отличие от ref для переменных, которые передаются с ключевым словам out, не требуется инициализация. И кроме того, вызываемый метод должен обязательно присвоить им значение.
Стоит отметить, что в версии C# 7.0 (Visual Studio 2017) можно определять переменные в непосредственно при вызове метода. То есть вместо:
int x = 10;
int area;
int perimetr;
GetData(x, 15, out area, out perimetr);
Console.WriteLine("Площадь: " + area);
Console.WriteLine("Периметр: " + perimetr);
Мы можем написать:
int x = 10;
GetData(x, 15, out int area, out int perimetr);
Console.WriteLine("Площадь: " + area);
Console.WriteLine("Периметр: " + perimetr);
Необязательные параметры
C# позволяет использовать необязательные параметры. Для таких параметров нам необходимо объявить значение по умолчанию. Также следует учитывать, что после необязательных параметров все последующие параметры также должны быть необязательными:
static int OptionalParam(int x, int y, int z=5, int s=4)
{
return x + y + z + s;
}
Так как последние два параметра объявлены как необязательные, то мы можем один из них или оба опустить:
static void Main(string[] args)
{
OptionalParam(2, 3);
OptionalParam(2,3,10);
Console.ReadLine();
}
Именованные параметры
В предыдущих примерах при вызове методов значения для параметров передавались в порядке объявления этих параметров в методе. Но мы можем нарушить подобный порядок, используя именованные параметры:
static int OptionalParam(int x, int y, int z=5, int s=4)
{
return x + y + z + s;
}
static void Main(string[] args)
{
OptionalParam(x:2, y:3);
//Необязательный параметр z использует значение по умолчанию
OptionalParam(y:2,x:3,s:10);
Console.ReadLine();
}