Действительно невозможный использовать перегрузку типа возврата?

Можно все еще использовать file.seek (0). Например, посмотрите на следующее:

import csv
file_handle = open("somefile.csv", "r")
reader = csv.reader(file_handle)
# Do stuff with reader
file_handle.seek(0)
# Do more stuff with reader as it is back at the beginning now

Это должно работать, так как csv.reader работает с тем же.

11
задан Motti 17 November 2009 в 19:17
поделиться

7 ответов

Как все уже сказали, ни один C # не поддерживает это. Фактически, причина, по которой IL поддерживает это, заключается в том, что вы должны четко указывать типы возвращаемых значений, как и параметры. Например, в IL можно сказать, что

ldarg.0
ldarg.1
call int AddNumbers(int, int)

IL на самом деле не имеет понятия о перегрузке метода: float AddNumbers (int, int) не имеет отношения к int AddNumbers (int, int ) как бы то ни было, что касается IL. Вы должны сообщить обо всем компилятору IL заранее, и он никогда не пытается сделать вывод о вашем намерении (как это делают языки более высокого уровня, такие как C #).

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

18
ответ дан 3 December 2019 в 00:46
поделиться

ECMA-334 C# Section 8.7.3

The signature of a method consists of the name of the method and the number, modifiers, and types of its formal parameters. The signature of a method не включает возвращаемый тип.

Вы можете использовать универсальный метод:

T AddNumbers<T>(int a, int b)
{
   if (typeof(T) == typeof(int) || typeof(T) == typeof(float))
   {
      return (T)Convert.ChangeType(a + b, typeof(T));
   }

   throw new NotSupportedException();
}
21
ответ дан 3 December 2019 в 00:46
поделиться

Да, это действительно невозможно в C #, я знаю, что C ++ не допускает этого, это связано с тем, как интерпретируется оператор:

double x = AddNumbers(1, 2);

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

Компилятор не может определить, какая версия наиболее подходит. Использование какого-то произвольного правила просто вызовет затруднения для поиска ошибок.

Это связано с этим простым утверждением:

double y = 5 / 2;  // y = 2.0
18
ответ дан 3 December 2019 в 00:46
поделиться

Проблема в том, что существует автоматическое преобразование из int в float, поэтому он действительно не знает, что вы намеревались. Вы намеревались вызвать метод, который принимает два int и возвращает int, а затем преобразовывать его в float, или вы намеревались вызвать метод, который принимает два int и возвращает float? Лучше иметь ошибку компилятора, чем сделать неправильный выбор и не сообщать вам, пока ваше приложение не сломается.

4
ответ дан 3 December 2019 в 00:46
поделиться

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

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

Для вашей игрушечной проблемы есть простые типовые решения. Например, ваш float AddNumbers (int, int) , скорее всего, всегда будет таким же, как (float) AddNumbers (int, int) , и в этом случае нет необходимости в вторая функция. Обычно этот случай обрабатывается с помощью обобщений: AddNumbers ( n1, n2) , поэтому вы получите float AddNumbers (float, float) и int AddNumbers (int, int) .

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

В тех немногих случаях, когда я хотел делать то, что вы хотите, на самом деле оказалось лучше назвать

Это также обсуждалось здесь .

Случай в MSIL / C # на http: // blogs. msdn.com/abhinaba/archive/2005/10/07/478221.aspx особенный, потому что они явные операторы преобразования.

2
ответ дан 3 December 2019 в 00:46
поделиться

Нет, нет способа сделать это. Фактически, кроме C ++ с шаблонами, ни один язык не поддерживает его. Это просто слишком опасно. И снова: что, если вы напишете

var a = AddNumbers(1, 1);

, какой тип a предположим?

Или что, если вы назовете это как

 double a = AddNumbers(1, 1);

или даже

 AddNumbers(1, 1);

, какую версию он должен вызывать?

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

class Program
{
    static int parse(int a) { return a; }
    static float parse(float a) { return a; }


    static void Main(string[] args)
    {
        double a = parse(1.0);
    }
}

. Если вы попытаетесь ее скомпилировать, компилятор выдаст вам ошибку

error C2668: 'parse' : ambiguous call to overloaded function
could be 'float parse(float)'

, потому что 1.0 имеет тип double , а компилятор действительно не знает, что type для выбора между int и float , поэтому он просит вас дать ему подсказку. Таким образом, вы можете просто преобразовать аргумент перед вызовом функции.

Но если функция перегружена именно возвращаемым типом, как тогда это сделать? Это просто невозможно сделать.

1
ответ дан 3 December 2019 в 00:46
поделиться

Как насчет передачи возвращаемого типа в качестве параметра с помощью указателей?

void AddNumbers(int a, int b, float *ret){
  *ret = (float)(a + b);
}

void AddNumbers(int a, int b, int *ret){
  *ret = (int)(a + b);
}

Его вызов будет выглядеть примерно так:

int a;
float b;
AddNumbers(1, 2, &a);
AddNumbers(1, 2, &b);
-3
ответ дан 3 December 2019 в 00:46
поделиться