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

Дубликат : перегрузка функции по типу возвращаемого значения?


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

public class MyClass
{
    private double d = 0;

    public double MyMethod()
    {
        return d;
    }

    public string MyMethod()
    {
        return d.ToString();
    }
}

Я получаю сообщение об ошибке компиляции, в котором говорится, что класс уже определяет член с такими же типами параметров.

(Очевидно, что то, как я использую это в своем коде, не так просто, как в моем примере кода ... но я думаю, что он передает идею.)

Я что-то упустил в объектно-ориентированном дизайне, что делает то, что я пытаюсь сделать, антипаттерном ООП? Конечно, компилятор должен уметь определять, какой метод я пытаюсь использовать, если я специально укажу ему, какой из них я хочу.

Учитывая, что MyClass myClass = new MyClass(); я ожидал, что будет работать следующий код:

double d = myClass.MyMethod();
string s = myClass.MyMethod();

Я ожидал, что следующий код будет иметь проблемы:

var v = myClass.MyMethod();

Но даже в этом случае var это должно привести к ошибке компиляции.

Кто-нибудь может увидеть, что я здесь делаю не так? Я более чем счастлив, что меня поправили. :-)

Ответов (5)

Решение

Это из-за приведения типов.

Допустим, у вас есть следующие функции:

int x(double);
float x(double);

double y = x(1.0);

Итак, какой из двух прототипов вам следует вызвать, особенно если они делают две совершенно разные вещи?

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

Итак, вы отметили свой вопрос, C# но я не вижу ничего плохого в разработке языка, который может делать то, что вы предлагаете. Одна из возможностей - пометить как ошибку любые неоднозначные команды, подобные приведенным выше, и заставить пользователя указать, какие из них следует вызывать, например, с помощью приведения:

int x(double);
float x(double);
double y = (float)(x(1.0));    // overload casting
double y = float:x(1.0);       // or use new syntax (looks nicer, IMNSHO)

Это может позволить компилятору выбрать правильную версию. Это даже сработает для некоторых вопросов, которые возникли в других ответах. Вы можете превратить двусмысленное:

System.out.Println(myClass.MyMethod());

в конкретное:

System.out.Println(string:myClass.MyMethod());

Это может быть возможно добавить, C# если это не слишком далеко в процессе стандартизации (и Microsoft прислушается), но я не думаю, что ваши шансы добавить это к ужасно большим усилиям C или C++ без них. Может быть, gcc было бы проще сделать это как расширение .

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

Строковое сообщение = "Результат =" + myClass.MyMethod ();

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

System.out.Println(myClass.MyMethod());

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

Нет ничего, что могло бы помешать вам вызвать свой метод без «захвата» возвращаемого типа. Вам ничто не мешает сделать это:

myClass.MyMethod();

Как компилятор узнает, какой из них вызывать в этом случае?

Изменить: добавив к этому, в С # 3.0, когда вы можете использовать var , как компилятор узнает, какой метод вы вызываете, когда вы это делаете:

var result = myClass.MyMethod();

Подпись метода - это только имя и входные параметры (тип и порядок). Тип возврата не является частью подписи. Таким образом, два метода с одинаковым именем и входными параметрами идентичны и конфликтуют друг с другом.