Вы столкнулись с динамическим заражением .dynamic
может быть чем угодно, поэтому любой метод или свойство может возвращать что угодно.Любой метод, которому вы передаете его, может быть любым, потому что, когда вы передаете dynamic
в качестве параметра, разрешение перегрузки происходит во время выполнения (это можно использовать, если вы ненавидите людей, которым придется поддерживать ваш код).
Если навести указатель мыши на Select
, он будет иметь тип Select<dynamic, string>
, поэтому он вернет IEnumerable<String>
.Поскольку ToString(dynamic d)
имеет явное приведение к string
в return
и возвращает тип string
, компилятор может быть уверен, что ToString
действительно возвращает строку.
IEnumerable<string> test = tmp.Select(ToString);
Кстати, если мы внесем эти изменения в ToString (), вышеприведенное все равно будет скомпилировано, а лямбда-версия по-прежнему не будет:
static string ToString(object d)
{
// Remove the cast to string
return d.ToString();
}
Заражение возникает, когда мысоздать tmp
как List<dynamic>
.
В лямбда-версии, которая не компилируется, при наведении курсора мыши мы на самом деле вызываем Select<dynamic, dynamic>
, который возвращает IEnumerable<dynamic>
.
Разрешение перегрузки выполняется во время выполнения, когда вы передаете dynamic
.Компилятор не может гарантировать во время компиляции, какой метод будет фактически вызван или что он вернет.Intellisense считает, что ToString
- это ваш статический метод, но компилятор не верит, что он останется верным.
IEnumerable<string> test2 = tmp.Select(x => ToString(x));
Это компилируется, потому что у нас есть приведение, где разрешение перегрузки не повлияет на него.
IEnumerable<string> test3 = tmp.Select(x => (string)ToString(x));
Джонатон Чейз любезно отмечает в комментариях, что мы заставляем его компилировать, явно передавая параметры типа в Select
:
IEnumerable<string> test4 = tmp.Select<dynamic, string>(x => ToString(x));
Важный вопрос, на мой взгляд,Вот почему ваш первый случай компилируется. Мое осторожное предположение состоит в том, что поскольку вы передаете ссылку на метод, а не вызываете его, динамическое разрешение перегрузки не происходит.
Считайте это заполнителем, пока кто-то с более глубоким пониманием не заинтересуется этим вопросом.