Компилятор C # не может определить параметры типа метода по ожидаемому типу возвращаемого значения? - PullRequest
6 голосов
/ 12 января 2011

Мне это кажется странным, но я помню поток, в котором Эрик Липперт прокомментировал невозможность (на мой взгляд, или, по крайней мере, соглашения) C # перегружать методы, основанные на типе возвращаемого значения, так что, возможно, это каким-то запутанным способом связанные с этим.

Есть ли причина, по которой это не работает:

public static T Test<T>() where T : new()
{
    return new T();
}

// Elsewhere
SomeObject myObj = Test();

Но это так:

 var myObj = Test<SomeObject>();

С определенной точки зрения, они оба хороши тем, что вы не повторяете себя (очень незначительным образом), но это просто другой проход компилятора?

Ответы [ 5 ]

5 голосов
/ 12 января 2011

Во-первых, это «перегрузка на основе типа возврата»:

void M(int x){...}
int M(int x){...}
string M(int x){...}

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

Причина в том, что тип возврата может быть тем, что вы пытаетесь выяснить .

M(Test());

Что такое тип возвратаиспытания?Это зависит от того, какую перегрузку мы выберем.Какую перегрузку М мы выбираем?Это зависит от типа возвращаемого значения Test.

В общем, C # спроектирован так, что каждое подвыражение имеет тип, а типы разрабатываются "изнутри" в направлении "снаружи", а не снаруживнутрь.

Примечательными исключениями являются анонимные функции, группы методов и null:

M(x=>x+1)

Какого типа x => x + 1?Это зависит от того, какая перегрузка M называется.

M(N); // N is a method group

Каков тип N?Опять же, это зависит от того, какая перегрузка M вызывается.

И так далее.В этих случаях мы делаем рассуждения «снаружи» и «внутрь».

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

4 голосов
/ 12 января 2011

За исключением выражений без типов (null, групп методов и лямбда-выражений), тип выражения должен определяться статически самим выражением независимо от контекста.

Другими словами, тип выражения Test() не может зависеть от того, для чего вы его назначаете.

3 голосов
/ 12 января 2011

Проверьте спецификацию языка C # §7.5.2, объявление типа переменной не является подтверждением для вывода типа, и, очевидно, это не должно быть. Рассмотрим следующий код:

Base b = Test<Derived>();
Derived d = Test<Derived>();

Тип возвращаемого значения метода, вероятно, отличается от объявленного типа переменной, поскольку у нас есть неявное преобразование в C #.

1 голос
/ 12 января 2011

Если вам нужен пример , почему тип выражения должен определяться самим выражением, рассмотрим два следующих случая:

  1. Мы вообще не используем возвращаемое значение - мы просто вызываем метод для его побочных эффектов.
  2. Мы передаем возвращаемое значение непосредственно в перегруженный метод

Использование «ожидаемого типа» возвращаемого значения, когда дело доходит до разрешения универсального типа, внесет в компилятор целый ряд дополнительных сложностей, и все, что вы получили, это то, что иногда вам нужно явно указать тип, а иногда Вы не можете, и можете ли вы изменить или нет, может измениться на основе несвязанных изменений в другом месте кода.

1 голос
/ 12 января 2011

Вывод типа компилятором не использует «ожидаемый тип» присваивания как часть логики.

Таким образом, «область рассмотрения» для вывода типа не такая:

SomeObject myObj = Test();

но это:

Test();

И здесь нет никаких подсказок относительно ожидаемого типа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...