Ранее мы рассмотрели, что из себя представляют объекты на c#, и как описываются свойства объектов. Однако объект, обладающий одними только свойствами зачастую бесполезен, потому как наравне с некоторыми параметрами объект обладает определенным набором операций, которые могут проводиться над ним, либо же выполняться самим объектом. Эти операции и называются методы C#.

Подпишись на группу Вконтакте и Телеграм-канал. Там еще больше полезного контента для программистов.
А на YouTube-канале ты найдешь обучающие видео по программированию. Подписывайся!

Смотрите моё видео на тему Методы C#

Методы C#

Методы описываются внутри класса, в следующем формате:

<модификатор доступа> <тип возвращаемого результата> <имя метода> ([параметры метода]) { <действия внутри метода> }.

Рассмотрим более подробно запись, приведенную выше. С модификаторами доступа мы познакомились ранее, ровно как и с типами данных. К примеру, если метод должен быть доступен для вызова извне, и возвращает значение строкового типа, мы получим подобную запись:

public string SomeMethod() { }.

Если же не предполагается возвращать результат работы метода, используется слово void. Параметры для методов так же указываются опционально. То есть их может и не быть совсем, как в нашем SomeMethod. Описываются параметры следующим образом: <тип данных> <название параметра>. Если бы в нашем методе были параметры, это выглядело бы примерно так.

public string SomeMethod(int firstParam, double secondParam, string thirdParam = "No") { }

Как вы могли заметить, третий параметр несколько отличается от первых двух — для него указано значение по умолчанию. Таким образом, мы можем вызывать SomeMethod, не указывая значение для третьего параметра. Также следует обратить внимание на правила именования методов и параметров. Microsoft рекомендуют использовать CamelCase при именовании методов (каждое слово с большой буквы) и pascalCase для переменных (первое слово с маленькой буквы, каждое последующее — с большой). И, разумеется, имена должны быть осмысленными и нести смысловую нагрузку. Комментарии, конечно, никто не отменял, но читать код с нормально именованными методами и переменными значительно приятнее и проще. Для методов, которые должны возвращать значение, необходимо указывать ключевое слово return. После этого слова должна идти переменная, значение которой возвращает метод. Например.

public string SayWhatAgain() 
{
    return "What?!"
}

Смысловой нагрузки этот код не несет (ну, разве что для фанатов фильма «Криминальное чтиво»).

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

Предположим, у нас есть метод, который в зависимости от набора переменных должен выполнять разные действия. К примеру:

public double Pow(double num) 

public double Pow(double num, double power)

Оба метода называются pow, однако первый вернет нам квадрат числа, а второй вернет число в степени power. Соответственно подобное написание и будет считаться перегрузкой метода. Если же мы попытаемся создать два метода с абсолютно идентичным набором параметров, типы данных и количество которых совпадают, IDE оповестит нас об ошибке. Так же существует более явная перегрузка методов при помощи ключевого слова override, однако об этом мы поговорим позднее.

Конструктор

Любой класс обладает некоторым набором свойств. А как корректно эти свойства установить при создании объекта класса? В данном случае на помощь приходит специальный метод — конструктор. Описывается он так:

public <Имя класса> ([параметры]) { }

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

Статичность

А если нам нужно вызвать метод класса не создавая для этого отдельный объект? В данном случае достаточно прописать этому методу ключевое слово static.

public static SomeMethod() { }

Таким образом, мы сможем совершенно спокойно работать с данным методом не создавая объект класса. Для вызова используется конструкция.

<Имя класса>.<Имя метода>

Статичным можем быть и целый класс. Однако в этом случае следует учесть ряд особенностей. Во-первых, для статического класса конструктор не имеет модификатора доступа и не перегружается. Так же объект статического класса существует в единственном числе для всей исполняемой программы. Но главным бонусом такого класса является возможность хранения состояния программы, которое было бы доступно из любой точки кода.

Рекурсивный вызов методов

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

Деструктор

Что произойдет с памятью, после того как объект класса отработает? По сути, она должна быть очищена. Так обычно и происходит. Однако, чтобы быть на сто процентов уверенными, мы можем создать метод-деструктор. Чтобы использовать ручной сбор мусора класс обязан реализовать интерфейс IDisposable. Интерфейсы мы рассмотрим несколько позднее.

Пример

Вернемся к нашему персонажу.

Персонаж с полосой hp

Рассмотрим код, который наделяет нашего персонажа набором методов для движения и выживания.

/// <summary>
/// Класс "Персонаж".
/// </summary>
public class Character
{
    private string _name;

    /// <summary>
    /// Имя персонажа.
    /// </summary>
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            if (!String.IsNullOrEmpty(value))
            {
                _name = value;
            }
            else
            {
                throw new ArgumentException($"Передана пустая строка: {nameof(_name)}");
            }
        }
    }

    private string _gender;

     /// <summary>
     /// Пол.
     /// </summary>
     public string Gender
     {
         get
         {
             return _gender;
         }
         set
         {
             if (!String.IsNullOrEmpty(value))
             {
                 _gender = value;
             }
             else
             {
                 throw new ArgumentException($"Передана пустая строка: {nameof(_gender)}");
             }
        }
    }

    private double _strength;

    /// <summary>
    /// Сила.
    /// </summary>
    public double Strength
    {
        get
        {
            return _strength;
        }
        set
        {
            if (value > 0)
            {
                _strength = value;
            }
            else
            {
                throw new ArgumentException("Сила не может быть меньше нуля.");
            }
        }
    }

    private double _agility;

    /// <summary>
    /// Сила.
    /// </summary>
    public double Agility
    {
        get
        {
            return _agility;
        }
        set
        {
            if (value > 0)
            {
                _agility = value;
            }
            else
            {
                throw new ArgumentException("Ловкость не может быть меньше нуля.");
            }
        }
    }

    private double _health;

    /// <summary>
    /// Сила.
    /// </summary>
    public double Health
    {
        get
        {
            return _health;
        }
        set
        {
            _health = value;
        }
    }

    /// <summary>
    /// Конструктор класса.
    /// </summary>
    /// <param name="name"> Имя персонажа. </param>
    /// <param name="gender"> Пол персонажа. </param>
    /// <param name="streght"> Сила (по умолчанию 10). </param>
    /// <param name="agility"> Ловкость (по умолчанию 7). </param>
    /// <param name="health"> Здоровье (по умолчанию 100). </param>
    public Character(string name, string gender, double strength = 10, double agility = 7, double health = 100)
    {
        Name = name;
        Gender = gender;
        Strength = strength;
        Agility = agility;
        Health = health;
    }

    /// <summary>
    /// Двигаться.
    /// </summary>
    /// <returns>Количество пройденных клеток на поле. </returns>
    public double Move()
    {
        return Agility;
    }

    /// <summary>
    /// Двигаться.
    /// </summary>
    /// <param name="bonus"> Бонус на передвижение.</param>
    /// <returns> Количество пройденных клеток.</returns>
    public double Mode(int bonus)
    {
        return Agility * bonus;
    }

    /// <summary>
    /// Атаковать персонажа.
    /// </summary>
    /// <param name="aim"> Цель атаки.</param>
    public void Hit(Character aim)
    {
        aim.Defend(Strength); 
    }

    /// <summary>
    /// Защищаться. 
    /// </summary>
    /// <param name="damage"> Наносимый урон.</param>
    public void Defend(double damage)
    {
        Health -= (damage / Agility);
    } 
}

Методы C# — Итоги

Итак, мы научили нашего персонажа ходить, бить, защищаться и даже перегрузили один метод и создали конструктор. Думаю, для старта этого должно быть достаточно. Удачных экспериментов, коллеги.

Кроме того, рекомендую прочитать статью Memento C# | Паттерн проектирования Хранитель C#. А также подписывайтесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для программистов.