Почему не сообщается о фактической ошибке?
Нет, это проблема;это означает , сообщая о фактической ошибке.
Позвольте мне объяснить немного более сложным примером.Предположим, у вас есть это:
class CustomerCollection
{
public IEnumerable<R> Select<R>(Func<Customer, R> projection) {...}
}
....
customers.Select( (Customer c)=>c.FristNmae );
ОК, что за ошибка в соответствии со спецификацией C # ?Вы должны внимательно прочитать спецификацию здесь.Давайте разберемся с этим.
У нас есть вызов Select как вызов функции с одним аргументом и без аргументов типа.Мы проводим поиск по Select в CustomerCollection, ища вызываемые объекты с именем Select, то есть такие, как поля типа делегата или методы.Поскольку у нас не указаны аргументы типа, мы сопоставляем любой универсальный метод Select.Мы находим один и строим из него группу методов.Группа методов содержит один элемент.
Теперь необходимо проанализировать группу методов по разрешению перегрузки, чтобы сначала определить набор кандидатов , а затем из этого определить применимый набор кандидатов , и из этого определяют лучший применимый кандидат , и из этого определяют окончательно утвержденный лучший применимый кандидат .Если какая-либо из этих операций завершается ошибкой, разрешение перегрузки должно завершиться с ошибкой.Какой из них терпит неудачу?
Мы начнем с построения набора кандидатов.Чтобы получить кандидата, мы должны выполнить вывод типа метода , чтобы определить значение аргумента типа R. Как работает вывод типа метода?
У нас есть лямбдачьи типы параметров все известны - формальным параметром является Customer.Чтобы определить R, мы должны сопоставить тип возврата лямбды с R. Какой тип возврата лямбды?
Мы предполагаем, что c - это Customer, и попыткапроанализировать лямбда-тело.При этом происходит поиск FristNmae в контексте Customer, и поиск завершается неудачей.
Следовательно, вывод типа лямбда-возврата завершается ошибкой, и к R. не добавляется граница.
После того, как все аргументы проанализированы, не существует границ для R. Следовательно, вывод типа метода не может определить тип для R.
Поэтому вывод типа метода завершается неудачно.
Поэтому в набор кандидатов не добавлен метод.
Следовательно, набор кандидатов пуст.
Следовательно, не может быть подходящих кандидатов.
Следовательно, сообщение об ошибке правильное здесь будет выглядеть примерно так: «При разрешении перегрузки не удалось найтиокончательно утвержденный лучший подходящий кандидат, потому что набор кандидатов был пуст. "
Клиенты будут очень недовольны этим сообщением об ошибке. Мы создали значительное количество эвристикв ошибкуАлгоритм создания отчетов, который пытается вывести более «фундаментальную» ошибку, которую пользователь мог бы предпринять, чтобы исправить ошибку.Мы рассуждаем:
Фактическая ошибка состоит в том, что набор кандидатов был пуст.Почему кандидат был пустым?
Поскольку в группе методов был только один метод, и вывод типа не удался.
ОК, если мысообщить об ошибке "Не удалось разрешить перегрузку из-за сбоя вывода типа метода"?Опять же, клиенты будут недовольны этим.Вместо этого мы снова задаем вопрос "почему не удалось сделать вывод типа метода?"
- Поскольку связанный набор R был пуст.
Это тоже паршивая ошибка.Почему границы были установлены пустыми?
- Поскольку единственным аргументом, по которому мы могли определить R, была лямбда, тип возвращаемого значения которой нельзя было вывести.
Хорошо, мы должны сообщить об ошибке "Не удалось разрешить перегрузку, поскольку вывод лямбда-типа возврата не смог определить тип возврата"? Опять , клиенты будут недовольны этим. Вместо этого мы задаем вопрос «почему лямбда не может определить тип возвращаемого значения?»
- Поскольку у Клиента нет члена с именем FristNmae.
И , что - это ошибка, о которой мы действительно сообщаем.
Итак, вы видите абсолютно извилистую цепочку рассуждений, которую мы должны пройти, чтобы выдать сообщение об ошибке, которое вы хотите. Мы не можем просто сказать, что пошло не так - этому разрешению перегрузки был дан пустой набор кандидатов - нам нужно копаться в прошлом, чтобы определить, как разрешение перегрузки попало в это состояние.
код, который делает это чрезвычайно сложный ; он имеет дело с более сложными ситуациями, чем та, которую я только что представил, включая случаи, когда существует n различных универсальных методов, и вывод типов не выполняется по m различным причинам, и мы должны выяснить из всех, что является «наилучшей» причиной для предоставления Пользователь. Напомним, что на самом деле существует дюжина различных типов выбора, и разрешение перегрузки для всех из них может не работать по разным причинам или по одной и той же причине.
В отчете об ошибках компилятора есть эвристика для обработки всех видов ошибок разрешения перегрузки; тот, который я описал, является лишь одним из них.
Итак, теперь давайте посмотрим на ваш конкретный случай. Что такое настоящая ошибка?
У нас есть группа методов с единственным методом, Foo. Можем ли мы построить набор кандидатов?
Да. Есть кандидат. Метод Foo является кандидатом на вызов, потому что он имеет каждый обязательный параметр, предоставленный - bar - и никаких дополнительных параметров.
ОК, в наборе кандидатов есть один метод. Есть ли подходящий член набора кандидатов?
Нет. Аргумент, соответствующий bar, не может быть преобразован в тип формального параметра, поскольку лямбда-тело содержит ошибку.
Таким образом, применимый набор кандидатов пуст, и, следовательно, нет окончательно подтвержденного наилучшего применимого кандидата, и, следовательно, разрешение перегрузки не выполняется.
Так в чем же должна быть ошибка? Опять же, мы не можем просто сказать, что «при разрешении перегрузки не удалось найти окончательно подтвержденного наиболее подходящего кандидата», потому что клиенты нас ненавидят. Мы должны начать копать сообщение об ошибке. Почему не удалось разрешить перегрузку?
- Поскольку применимый набор кандидатов был пуст.
Почему он был пуст?
- Потому что каждый кандидат в нем был отклонен.
Был ли лучший кандидат?
- Да, был только один кандидат.
Почему он был отклонен?
- Поскольку его аргумент не был преобразован в формальный тип параметра.
Хорошо, на данный момент, по-видимому, эвристика, которая обрабатывает проблемы с разрешением перегрузки, которые включают именованные аргументы, решает, что мы выкопали достаточно далеко и что об этой ошибке мы должны сообщить. Если у нас нет именованных аргументов, тогда некоторые другие эвристические запросы:
Почему аргумент не обратим?
- Поскольку лямбда-тело содержало ошибку.
И тогда мы сообщаем об этой ошибке.
Ошибка эвристики не совершенна ;отнюдь не.По совпадению, я на этой неделе делаю серьезную реархитектуру "простой" эвристики отчетов об ошибках разрешения перегрузки - просто такие вещи, как когда говорят "не было метода, который принял 2 параметра", а когда говорят "метод, который вы хотите, является частными когда сказать «нет параметра, соответствующего этому имени» и т. д .;вполне возможно, что вы вызываете метод с двумя аргументами, нет открытых методов с таким именем с двумя параметрами, есть один, который является закрытым, но у одного из них есть именованный аргумент, который не совпадает.Быстро, какую ошибку мы должны сообщить?Мы должны сделать лучшее предположение, и иногда есть лучшее предположение, которое мы могли бы сделать, но не были достаточно изощренными, чтобы сделать это.
Даже получить такое право оказывается очень сложной работой.Когда мы в конечном итоге дойдем до реструктуризации большой тяжелой эвристики - например, как справляться с ошибками вывода типа метода внутри выражений LINQ - я вернусь к вашему случаю и посмотрим, сможем ли мы улучшить эвристику.
Но поскольку полученное вами сообщение об ошибке полностью правильное , это не ошибка в компиляторе;скорее это просто недостаток эвристики сообщения об ошибках в конкретном случае.