Что такое перегрузка методов c
Перегрузка методов
В этой статье я доступным языком расскажу о механизме перегрузки методов в C#. О том, что из себя представляет данных механизм, как и когда им пользоваться. Методы в C#, это подпрограммы, которые создаются для многократного выполнения однотипных действий. Часто, программисту приходится сталкиваться с ситуациями, когда необходимо выполнять однотипные действия над разными по типу входными параметрами, или над разным количеством параметров… Представим, что нам нужно написать метод, который принимает два целочисленных аргумента и возвращает их сумму. Выглядеть этот метод может примерно так:
//Получает два целых числа и возвращает их сумму static int Sum(int aFirstArg, int aSecondArg)
И все бы ничего, но нам может понадобиться создать еще один метод, который принимает в качестве параметров не целые числа, а вещественные, но выполняет ту же функцию, или метод, который принимает не два, а три параметра. В таком случае, нам нужно придумать для каждого такого метода свое, уникальное и более или менее соответствующее название! А это уже как минимум, напрягает программиста, который склонен решать какие-то практические задачи, а не выбирать имена методам… Так вот, механизм перегрузки методов избавляет программиста от подобных проблем, а именно, позволяет создавать методы с одним и тем же именем, но с разным списком аргументов. Причем отличаться обязательно должны именно аргументы методов, возвращаемое значение тут не учитывается.
Отличаться списки аргументов должны либо типами аргументов, либо количеством аргументов, ну или и тем, и другим, но не просто именами аргументов.
Вот пример допустимой перегрузки метода «Sum»:
//Получает два целых числа и возвращает их сумму static int Sum(int aFirstArg, int aSecondArg) < return aFirstArg + aSecondArg; >//Получает три целых числа, и возвращает их сумму static int Sum(int aFirstArg, int aSecondArg, int aThirdArg) < return aFirstArg + aSecondArg + aThirdArg; >//Получает два вещественных числа и возвращает их сумму static double Sum(double aFirstArg, double aSecondArg)
А вот так уже нельзя перегружать тот же метод:
//Получает два целых числа и возвращает их сумму static int Sum(int aFirstArg, int aSecondArg) < return aFirstArg + aSecondArg; >//Так перегружать метод Sum нельзя static long Sum(int aFirstArg, int aSecondArg) < return aFirstArg + aSecondArg; >//Так перегружать метод Sum нельзя static int Sum(int aAgr1, int Arg2)
А всё это по тому, что компилятор «смотрит» на количество и типы аргументов методов (не учитывая имена аргументов и возвращаемое значение). И все это для того, чтобы компилятор однозначно «понимал», какой конкретно метод нужно вызывать в определенной ситуации. Если Вы вызовете метод «Sum», передав туда два целых числа, то вызовется первый метод, а если передадите два вещественных числа, то уже третий.
Перегрузка методов – одна из форм полиморфизма. Полиморфизм – один из основных принципов ООП, хотя и не самая крутая.
Таким образом, программист получает дополнительные возможности при создании методов, но нужно помнить, что иметь возможность – еще не значит обязательно ею пользоваться. Иногда лучше создать отдельный метод со своим уникальным именем, хотя, иногда – это только иногда… Но в любом случае, знать, что такое перегрузка методов и как её использовать нужно непременно!
Добавить комментарий Отменить ответ
Для отправки комментария вам необходимо авторизоваться.
Перегрузка методов
В C# допускается совместное использование одного и того же имени двумя или более методами одного и того же класса, при условии, что их параметры объявляются по-разному. В этом случае говорят, что методы перегружаются, а сам процесс называется . Перегрузка методов относится к одному из способов реализации полиморфизма в C#.
В общем, для перегрузки метода достаточно объявить разные его варианты, а об остальном позаботится компилятор. Но при этом необходимо соблюсти следующее важное условие: тип или число параметров у каждого метода должны быть разными.
Совершенно недостаточно, чтобы два метода отличались только типами возвращаемых значений. Они должны также отличаться типами или числом своих параметров. (Во всяком случае, типы возвращаемых значений дают недостаточно сведений компилятору C#, чтобы решить, какой именно метод следует использовать.) Разумеется, перегружаемые методы могут отличаться и типами возвращаемых значений. Когда вызывается перегружаемый метод, то выполняется тот его вариант, параметры которого соответствуют (по типу и числу) передаваемым аргументам.
Давайте рассмотрим пример использования перегрузки методов:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 < class UserInfo < // Перегружаем метод ui public void ui() < Console.WriteLine("Пустой метод\n"); >public void ui(string Name) < Console.WriteLine("Имя пользователя: ",Name); > public void ui(string Name, string Family) < Console.WriteLine("Имя пользователя: \nФамилия пользователя: ",Name,Family); > public void ui(string Name, string Family, byte Age) < Console.WriteLine("Имя пользователя: \nФамилия пользователя: \nВозраст: ", Name, Family, Age); > > class Program < static void Main(string[] args) < UserInfo user1 = new UserInfo(); // Разные реализации вызова перегружаемого метода user1.ui(); user1.ui("Ерохин", "Александр", 26); Console.ReadLine(); >> >
Как видите метод ui перегружается три раза. Модификаторы параметров ref и out также учитываются, когда принимается решение о перегрузке метода. Несмотря на то что модификаторы параметров ref и out учитываются, когда принимается решение о перегрузке метода, отличие между ними не столь существенно. Давайте добавим еще одну перегрузку в вышеуказанный пример:
// Используем модификатор параметров public void ui(string Name, string Family, ref byte Age)
Перегрузка методов поддерживает свойство полиморфизма, поскольку именно таким способом в C# реализуется главный принцип полиморфизма: один интерфейс — множество методов. Для того чтобы стало понятнее, как это делается, обратимся к конкретному примеру. В языках программирования, не поддерживающих перегрузку методов, каждому методу должно быть присвоено уникальное имя. Но в программировании зачастую возникает потребность реализовать по сути один и тот же метод для обработки разных типов данных.
Допустим, что требуется функция, определяющая абсолютное значение. В языках, не поддерживающих перегрузку методов, обычно приходится создавать три или более вариантов такой функции с несколько отличающимися, но все же разными именами. Например, в С функция abs() возвращает абсолютное значение целого числа, функция labs() — абсолютное значение длинного целого числа, а функция fabs () — абсолютное значение числа с плавающей точкой обычной (одинарной) точности.
В С перегрузка не поддерживается, и поэтому у каждой функции должно быть свое, особое имя, несмотря на то, что все упомянутые выше функции, по существу, делают одно и то же — определяют абсолютное значение. Но это принципиально усложняет положение, поскольку приходится помнить имена всех трех функций, хотя они реализованы по одному и тому же основному принципу. Подобные затруднения в C# не возникают, поскольку каждому методу, определяющему абсолютное значение, может быть присвоено одно и то же имя. И действительно, в состав библиотеки классов для среды .NET Framework входит метод Abs(), который перегружается в классе System.Math для обработки данных разных числовых типов. Компилятор C# сам определяет, какой именно вариант метода Abs() следует вызывать, исходя из типа передаваемого аргумента.
В C# определено понятие сигнатуры, обозначающее имя метода и список его параметров; Применительно к перегрузке это понятие означает, что в одном классе не должно существовать двух методов с одной и той же сигнатурой. Следует подчеркнуть, что в сигнатуру не входит тип возвращаемого значения, поскольку он не учитывается, когда компилятор C# принимает решение о перегрузке метода. В сигнатуру не входит также модификатор params.
Чтобы закрепить понятие перегрузки методов, давайте рассмотрим перегрузку встроенного метода IndexOf класса String пространства имен System:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 < class Program < static void Main(string[] args) < string s = "Всем привет, это сайт professorweb.ru :)"; char ch = 'е'; string smile = ":)"; Console.WriteLine("Исходная строка: \n\n----------------------\n",s); // Первая перегрузка if (s.IndexOf(ch) != -1) Console.WriteLine("Символ '' находится на позиции ",ch,s.IndexOf(ch)); // Вторая перегрузка if (s.IndexOf(ch, s.IndexOf(ch)+1) != -1) Console.WriteLine("Далее, этот символ встречается на позиции ", s.IndexOf(ch, s.IndexOf(ch) + 1)); // Третья перегрузка if (s.IndexOf(smile, 0, s.Length) != -1) Console.WriteLine("Смайл найден на позиции ", smile, s.IndexOf(smile, 0, s.Length)); // Четвертая перегрузка if (s.IndexOf(smile, StringComparison.Ordinal) != -1) Console.WriteLine("Теперь смайл найден другим способом"); Console.ReadLine(); > > >
В данном примере используется только часть доступных перегрузок метода IndexOf, если бы C# не поддерживал перегрузки, то пришлось бы присваивать каждому методу свое имя, что конечно же очень неудобно. В данном случае метод IndexOf реализует несколько перегрузок, для поиска символов и подстрок в исходной строке.
Перегрузка методов
Перегрузка методов – создание одноименных методов в пределах одного класса, которые отличаются количеством и/или типом параметров. Перегруженные методы могут возвращать значения разных типов данных, однако отличие только в возвращаемом типе не допускается.
Сигнатуры
Сигнатура метода – это часть объявления метода, которая позволяет компилятору идентифицировать метод среди других.
В сигнатуру входят:
- Имя метода;
- Количество параметров;
- Порядок параметров;
- Тип параметров;
- Модификаторы параметров.
Названия параметров и тип возвращаемого значения не относится к сигнатуре.
Опираясь на сигнатуру, компилятор выбирает метод, который нужно использовать.
Рассмотрим несколько методов:
int Div(int a, int b) < return a / b; > uint Sum(uint x, uint y, uint z) < return x + y + z; >
Метод Div имеет следующую сигнатуру – Div(int, int), а метод Sum – Sum(uint, uint, uint).
Перегрузка
Исходя из понятия сигнатуры, перегруженными называют методы, которые отличаются сигнатурами, но при этом имеют одинаковые имена.
public int Mult(int a, int b) < return a * b; > public double Mult(double x, double y) < return x * y; > public double Mult(double x, double y, double z) < //вызывает предыдущий метод return Mult(x, y) * z; > public string Mult(string s, uint k) < var retVal = string.Empty; for (var i = 0; i < k; i++) < retVal += s; >return retVal; >
Как можно заметить, в каждом из рассмотренных примеров использована уникальная сигнатура.
C# также поддерживает сокращенную запись перегруженных методов:
float F(float x) => x - 2 / x; int F(int x) => x - 2 / x;
При вызове метода с использованием литералов, можно указывать их тип с помощью суффиксов:
var r1 = F(3); //3 var r2 = F(3f); //2.33
Перегруженные методы могут отличаться только модификаторами:
int PlusOne(int i) < return i + 1; > int PlusOne(ref int i) < i++; return i; >
Для чего использовать перегрузку методов
Перегрузка используется для создания универсальных методов, логика поведения которых одинакова, но типы данных или количество аргументов разное. Это дает возможность писать красивый код, группируя методы с одинаковым поведением по имени.
Рассмотрим пример поиска минимального значения из двух целых чисел:
static int Min(int n1, int n2) < return n1
Используя перегрузку можно увеличить количество аргументов, для нахождения минимального из трех чисел:
static int Min(int n1, int n2, int n3) < //вызов предыдущего метода var m = Min(n1, n2); return m
Вызов перегруженных методов:
static void Main(string[] args) < Console.WriteLine(Min(3, -2)); Console.WriteLine(Min(6, 4, 2)); Console.ReadLine(); >
Ограничения при перегрузке методов
Локальные функции
C# не поддерживает перегрузку локальных функций, поэтому такой код не скомпилируется:
public void MyMethod( ) < string Hello(string name) => "Hi! " + name; string Hello(string firstName, string lastName) => "Hello! " + firstName + " " + lastName; Console.WriteLine(Hello("John")); Console.WriteLine(Hello("James", "Smith")); >
Отличие только по возвращаемому типу
Нельзя перегружать методы, если они отличаются только по типу возвращаемого значения.
Следующий код не скомпилируется:
void DisplayNumber(long l) < Console.Write(l); >long DisplayNumber(long l) < Console.WriteLine(l); return l; >
Методы с опциональными параметрами
Рассмотрим метод с параметрами по умолчанию:
static void ShowSum(byte a, byte b, byte c = 5)
Может показаться, что к этому методу подходят сразу две сигнатуры: ShowSum(byte, byte, byte) и ShowSum(byte, byte), но это не так, подходит только первый вариант. Поэтому если перегрузить его методом с двумя параметрами:
static void ShowSum(byte x, byte y)
он будет иметь больший приоритет, и аргумент по умолчанию не используется. Выйти из ситуации можно используя именованные параметры:
ShowSum(2, 3); //5, а не 10, как можно ожидать ShowSum(2, 3, 1); //6 ShowSum(a: 2, b: 3); //10
Хотя при разработке программ, таких конструкций лучше избегать, потому что они вносят неоднозначность.
На практике перегрузки встречаются очень часто. К примеру метод Console.Write(), универсальный метод, который может принимать разное количество аргументов разного типа данных, при этом поведение его во всех случаях одинакова – вывод значений на экран консольного приложения.
Урок #23 – Перегрузка методов в языке C#
За счет перегрузки методов мы можем использовать одно имя метода для нескольких разных методов/функций. За урок мы научимся применять эту технологию на практике и узнаем зачем вообще она нужна.
Видеоурок
С перегрузкой методов мы уже ни раз сталкивались, хотя ни разу их не создавали вручную. Пришло время это исправить.
Что такое перегрузка методов?
За счёт перегрузки методов мы можем создать множество методов, что будут принимать разное количество параметров или разный тип данных и при этом будут иметь одно и то же имя.
Отличным примером является метод «Write» или «WriteLine». В данный метод мы можем передавать различные типы данных, но при этом вывод информации происходит без каких-либо ошибок. Так происходит из-за того, что в классе Console есть множество перегрузок методов «Write» и «WriteLine».
Как создать перегрузку?
Чтобы создать перегрузку необходимо прописать метод с тем же именем, но при этом указать либо другое количество принимаемых параметров, либо другие типы данных для принимаемых параметров.
public static string getInfo(string some) < return some + "!"; >public static int getInfo(int a, int b)
Теперь при вызове метода компилятор будет понимать какие параметры были переданы и в зависимости от этого будут вызываться разные методы.