Під час написання програм, деякі рядки з інструкціями повторюються, для того, щоб зменшити кількість коду, покращити читабельність та спростити повторне використання цих інструкцій, їх можна об’єднати в метод.
Метод – це конструкція у вигляді блоку коду, яка виконує певні дії, та має закінчене смислове навантаження. Аналогом методів мови C#, є математичні функції.
В деяких мовах програмування, розділяють функції та процедури. В мові C#, такого розділення немає, хоча умовно можна вважати функціями методи, які повертають значення, а процедурами – методи, що не повертають значень.
Синтаксично метод виглядає наступним чином:
<modifiers> type name(<parameters>)
{
//тіло методу
}
- modifiers – необов’язкові модифікатори доступу;
- type – тип даних, які повертаються:
- якщо метод не повертає значень, то використовується тип void;
- якщо повертає, то в тілі методу, повинно бути присутнє, ключове слово return, після якого вказують значення(того ж типу, що і метод), яке повертається;
- name – ім’я методу;
- parameters – необов’язкові параметри(аргументи).
Розглянемо приклади методів:
using System;
class Program
{
static void PrintHelloWorld()
{
Console.WriteLine("Hello World!");
}
static void PrintHello(string name)
{
var text = "Hello " + name + "!";
Console.WriteLine(text);
}
static int Cube(int x)
{
return x * x * x;
}
static void Main(string[] args)
{
PrintHelloWorld();
PrintHello("Andrew");
var b1 = Cube(2); //8
var b2 = Cube(3); //27
Console.ReadLine();
}
}
Всі три методи викликаються в основному методі програми – Main. Вони мають модифікатори доступу static. Перші два методи типу void, тобто нічого не повертають.
PrintHelloWorld – викликає Console.WriteLine з текстовим параметром.
PrintHello – приймає в якості аргументу текстовий рядок і після модифікації тексту, передає його в інший метод Console.WriteLine, який виводить текст в консоль.
Cube – приймає на вхід ціле число, підносить його до кубу, та повертає результат.
Коли використовувати методи
Якщо частина коду повторюється два і більше рази, то є сенс винести інструкції в окремий метод. Розглянемо приклад вводу масиву з клавіатури:
var a = new int[10];
var b = new int[7];
for (int i = 0; i < a.Length; i++)
{
Console.Write($"a[{i}] = ");
a[i] = Convert.ToInt32(Console.ReadLine());
}
for (int i = 0; i < b.Length; i++)
{
Console.Write($"b[{i}] = ");
b[i] = Convert.ToInt32(Console.ReadLine());
}
Як бачимо, код для заповнення масивів дублюється, тому ми можемо створити метод для заповнення масиву значеннями, що вводяться з клавіатури:
static int[] GetArrayFromConsole(string arrayName, int elementCount)
{
var retVal = new int[elementCount];
for (int i = 0; i < retVal.Length; i++)
{
Console.Write($"{arrayName}[{i}] = ");
retVal[i] = Convert.ToInt32(Console.ReadLine());
}
return retVal;
}
Як аргументи, методу передаються: назва масиву та кількість елементів(довжина).
Після цього, метод можна багаторазово використовувати, для створення нових масивів цілих чисел, які вводить користувач:
static void Main(string[] args)
{
int[] t = GetArrayFromConsole("t", 5);
var g = GetArrayFromConsole("g", 4);
}
Оператор return
Оператор return завершує виконання методу, та може повертати значення. Інструкції розміщені після return ігноруються. В методі дозволяється багатократне використання оператора return, однак інколи це ускладнює читання коду програми. Якщо метод має тип void – оператор return може використовуватись для дострокового виходу:
static void Test(int i)
{
if (i <= 0 || i > 5)
{
return;
Console.Write("123"); //цей рядок завжди ігнорується
}
Console.WriteLine(i);
}
static string ZeroCompare(double number)
{
if (number < 0)
{
return "Число менше нуля";
}
else if (number > 0)
{
return "Число більше нуля";
}
return "Число рівне нулю";
}
Параметри методів
Параметри методу дозволяють передавати в нього деякі вхідні дані. Під час виклику методу, параметри передаються в тому ж порядку, в якому вони описані. Тобто значення аргументу присвоюється параметру в залежності від його позиції в списку параметрів.
Передача параметрів по значенню
Для примітивних типів даних передача параметрів відбувається по значенню. Тобто в якості аргументу передається копія даних. В тілі методу, ми можемо змінювати змінні параметрів, при цьому зміни ніяк не впливають на передані дані:
using System;
class Program
{
static int Add(int x1, int x2)
{
x1 += x2; //зміна x1 не впливає на передану в якості аргументу змінну num1
return x1;
}
static void Main(string[] args)
{
var num1 = 2;
var num2 = 5;
var sum = Add(num1, num2);
Console.WriteLine($"{num1} + {num2} = {sum}");
Console.ReadLine();
}
}
Передача параметрів по посиланню
Для передачі змінних за посиланням, використовується модифікатор ref. Якщо параметр позначений ключовим словом ref, то будь які зміни цього параметру в тілі методу, відображаються на передану змінну:
using System;
class Program
{
static int Mult(ref int x1, int x2)
{
x1 *= x2; //зміна x1 впливає на змінну n1
return x1;
}
static void Main(string[] args)
{
var n1 = 24;
var n2 = 4;
var mult = Mult(ref n1, n2);
//змінна n1 містить нове значення
Console.WriteLine($"{n1}");
Console.ReadLine();
}
}
Модифікатор ref вказується як в описі, так і при виклику методу.
Вихідні параметри
Вище розглянуті параметри мають назву вхідні, оскільки передаються на вхід методу. Крім цього, в мові C#, є вихідні параметри. Для того, щоб позначити параметр як вихідний, використовується модифікатор out.
Розглянемо метод для ділення двох чисел, він повертає текст помилки, якщо ділення не можливе, а в якості вихідного параметру – результат операції:
using System;
class Program
{
static string Div(int a, int b, out int result)
{
if (b == 0)
{
result = int.MinValue;
return "На нуль ділити не можна!";
}
else
{
result = a / b;
return "";
}
}
static void PrintResult(string errorText, int res)
{
if (string.IsNullOrEmpty(errorText))
{
Console.WriteLine(res);
}
else
{
Console.WriteLine(errorText);
}
}
static void Main(string[] args)
{
int r1;
var err1 = Div(64, 8, out r1);
PrintResult(err1, r1);
//змінна r2 оголошується в списку аргументів
var err2 = Div(34, 0, out int r2);
PrintResult(err2, r2);
Console.ReadLine();
}
}
Як видно з прикладу, C# 7.0 підтримує дві рівнозначні форми синтаксису для запису вихідних параметрів:
- змінна оголошується перед викликом методу;
- змінна оголошується в списку аргументів.
Вихідному параметру, в тілі методу, обов’язково повинно бути присвоєне значення.
Як і у випадку з ref, модифікатор out вказується в описі та при виклику методу.
Іменовані аргументи
В C# є можливість передавати параметри в довільному порядку, для цього використовуються іменовані аргументи(named arguments). Щоб явно вказати ім’я аргументу, використовується наступний синтаксис:
arg_name : arg_value
Приклад програми з іменованими аргументами:
static string GetPrettyName(string firstName, string lastName)
{
return firstName + " " + lastName;
}
static void Main(string[] args)
{
var s = GetPrettyName(lastName: "Jackson", firstName: "Anna");
}
Опціональні параметри
В методах можна використовувати необов’язкові чи опціональні параметри, які мають задане за змовчуванням значення.
Розглянемо приклад методу, для розрахунку процентів по депозитному вкладу в банку. Зазвичай депозитна ставка 10%, крім того постійні клієнти можуть отримати бонус:
static decimal CalcDeposit(decimal sum, decimal percent = 10m, decimal bonus = 0m)
{
return sum + sum * ((percent + bonus) / 100m);
}
Приклад використання розрахунку:
//депозит з ставкою та бонусом за замовчуванням
var d1 = CalcDeposit(10000);
//нараховано бонус 2.5% (передається як іменований аргумент), ставка за замовчуванням - 10%
var d2 = CalcDeposit(15000, bonus: 2.5m);
//збільшено процентну ставку та бонус
var d3 = CalcDeposit(20000, 15m, 3m);
Необов’язкові параметри повинні бути останніми у списку аргументів методу.
Скорочений запис методів
Починаючи з C# 6.0, методи, що містять тільки одну інструкцію, можна записувати в скороченій формі через лямбда-вирази, що дає змогу значно скоротити кількість написаного коду.
Наприклад математичну функцію y = x2 - 2/x, можна записати:
static double Y(double x)
{
return x * x - 2 / x;
}
Використавши лямбда-вираз, код буде мати наступний вигляд:
static double Y(double x) => x * x - 2 / x;
Аналогічним чином можна спрощувати методи, які не повертають значень:
static void DisplayHello(string n)
{
Console.WriteLine("Привіт {0}!", n);
}
Скорочується до:
static void DisplayHello(string n) => Console.WriteLine("Привіт {0}!", n);
Локальні функції
В версії C# 7.0, з’явилась можливість використовувати методи вкладені в метод, такі конструкції мають назву – локальні функції.
Вони підтримують як класичну, так і спрощену форму синтаксису:
static void Main(string[] args)
{
//максимальне з цілих двох чисел
int Max(int a, int b)
{
if (a > b)
return a;
return b;
}
// мінімальне з двох цілих чисел
int Min(int c, int d) => c < d ? c : d;
var t1 = Max(13, 22);
var t2 = Min(42, 56);
}
Для всіх розглянутих методів використовується модифікатор static, оскільки передбачається їх безпосереднє використання в головному методі програми – Main.