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

Метод – это конструкция в виде блока кода, которая выполняет некоторые действия, и имеет логическую смысловую нагрузку. Аналогом методов языка 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.

Смотрите также: