В C# допускается совместное использование одного и того же имени двумя или более методами одного и того же класса, при условии, что их параметры объявляются по-разному. В этом случае говорят, что методы перегружаются, а сам процесс называется перегрузкой методов. Перегрузка методов относится к одному из способов реализации полиморфизма в С#.
Но при этом необходимо соблюсти следующее важное условие: тип или число параметров у каждого метода должны быть разными.
Когда вызывается перегружаемый метод, то выполняется тот его вариант, параметры которого соответствуют (по типу и числу) передаваемым аргументам.
//продемонстрировать перегрузку методов.
using System;
class Overload
{
public void OvlDemo()
{
Console.WriteLine("Без параметров");
}
//перегрузка метода OvlDemo с одним целочисленным параметром.
public void OvlDemo(int a)
{
Console.WriteLine("Один параметр: " + a);
}
//перегрузка метода OvlDemo с двумя целочисленными параметрами.
public int OvlDemo(int a, int b)
{
Console.WriteLine("Два параметра: " + a + " " + b);
return a + b;
}
|
|
//перегрузка метода OvlDemo с двумя параметрами типа double.
public double OvlDemo(double a, double b)
{
Console.WriteLine("Два параметра типа double: " + a + " " + b);
return a + b;
}
}
class OverloadDemo
{
static void Main()
{
Overload ob = new Overload();
int resI;
double resD;
//вызвать все варианты метода OvlDemo();
ob.OvlDemo();
Console.WriteLine();
ob.OvlDemo(2);
Console.WriteLine();
resI = ob.OvlDemo(4, 6);
Console.WriteLine("Результат вызова метода ob.OvlDemo(4, 6): " + resI);
Console.WriteLine();
resD = ob.OvlDemo(1.1, 2.32);
Console.WriteLine("Результат вызова метода ob.OvlDemo(1.1, 2.32): " + resD);
}
}
Попытка использовать два разных (по типу возвращаемого значения) варианта метода OvlDemo() в приведенном ниже фрагменте кода приведет к ошибке.
// Одно объявление метода OvlDemo(int) вполне допустимо.
public void OvlDemo(int a)
{
Console.WriteLine("Один параметр: " + a);
}
/* Ошибка! Два объявления метода OvlDemo(int) не допускаются,
хотя они и возвращают разнотипные значения. */
public int OvlDemo(int a)
{
Console.WriteLine("Один параметр: " + a);
return a * a;
}
И как пояснялось в главе 3, в C# предусмотрен ряд неявных (т.е. автоматических) преобразований типов. Эти преобразования распространяются также на параметры перегружаемых методов.
//неявные преобразования типов могут повлиять на решение перегружать метод.
using System;
class Overload2
{
public void MyMeth(int x)
{
Console.WriteLine("В методе MyMeth(int): " + x);
}
public void MyMeth(double x)
{
Console.WriteLine("В методе MyMeth(double): " + x);
}
}
class TypeConv
{
static void Main()
{
Overload2 ob = new Overload2();
int i = 10;
double d = 10.1;
byte b = 99;
short s = 10;
float f = 11.5F;
ob.MyMeth(i); //вызвать ob.MyMeth(int)
ob.MyMeth(d); //вызвать ob.MyMeth(double)
ob.MyMeth(b); //вызвать ob.MyMeth(int) -- с преобразованием типа
ob.MyMeth(s); //вызвать ob.MyMeth(int) -- с преобразованием типа
ob.MyMeth(f); //вызвать метод ob.MyMeth(double) -- с преобразованием типа
|
|
}
}
В данном примере определены только два варианта метода MyMeth(): с параметром типа int и с параметром типа double. Тем не менее методу MyMeth() можно передать значение типа byte, short или float. Так, если этому методу передается значение типа byte или short, то компилятор C# автоматически преобразует это значение в тип int и в итоге вызывается вариант MyMeth(int) данного метода. А если ему передается значение типа float, то оно преобразуется в тип double и в результате вызывается вариант MyMeth(double) данного метода.
Следует, однако, иметь в виду, что неявные преобразования типов выполняются лишь в том случае, если отсутствует точное соответствие типов параметра и аргумента. В качестве примера ниже приведена чуть измененная версия предыдущей программы, в которую добавлен вариант метода MyMeth(), где указывается параметр типа byte.
// Добавить метод MyMeth(byte).
using System;
class Overload2
{
public void MyMeth(byte x)
{
Console.WriteLine("В методе MyMeth(byte): " + x);
}
public void MyMeth(int x)
{
Console.WriteLine("В методе MyMeth(int): " + x);
}
public void MyMeth(double x)
{
Console.WriteLine("В методе MyMeth(double): " + x);
}
}
class TypeConv
{
static void Main()
{
Overload2 ob = new Overload2();
int i = 10;
double d = 10.1;
byte b = 99;
short s = 10;
float f = 11.5F;
ob.MyMeth(i); // вызвать метод ob.MyMeth(int)
ob.MyMeth(d); // вызвать метод ob.MyMeth(double)
ob.MyMeth(b); // вызвать метод ob.MyMeth(byte) --// на этот раз без преобразования типа
ob.MyMeth(s); // вызвать метод ob.MyMeth(int) -- с преобразованием типа
ob.MyMeth(f); // вызвать метод ob.MyMeth(double) -- с преобразованием типа
}
}
Оба модификатора параметров, ref и out, также учитываются, когда принимается решение о перегрузке метода. В качестве примера ниже приведен фрагмент кода, в котором определяются два совершенно разных метода.
public void MyMeth(int x)
{
Console.WriteLine("В методе MyMeth(int): " + x);
}
public void MyMeth(ref int x)
{
Console.WriteLine("В методе MyMeth(ref int): " + x);
}
Следовательно, при обращении
ob.MyMeth(i);
вызывается метод MyMeth(int x), но при обращении
ob.MyMeth(ref i)
вызывается метод MyMeth(ref int x)
Несмотря на то что модификаторы параметров ref и out учитываются, когда принимается решение о перегрузке метода, отличие между ними не столь существенно. Например, два следующих варианта метода MyMeth() оказываются недействительными.
// Неверно!
public void MyMeth(out int x) { //...
public void MyMeth(ref int x) { //...
В данном случае компилятор не в состоянии различить два варианта одного и того же метода MyMeth() только на основании того, что в одном из них используется параметр out, а в другом — параметр ref.
В C# определено понятие сигнатуры, обозначающее имя метода и список его параметров, Применительно к перегрузке это понятие означает, что в одном классе не должно существовать двух методов с одной и той же сигнатурой. Следует подчеркнуть, что в сигнатуру не входит тип возвращаемого значения, поскольку он не учитывается, когда компилятор C# принимает решение о перегрузке метода. В сигнатуру не входит также модификатор params.