Я недавно играл с Massive, Micro-ORM, который возвращает коллекции IEnumerable .
Я обнаружил неожиданную проблему, когда попытался запросить одну из этих коллекций с помощью LINQ.
Хотя у компилятора, похоже, нет проблем с обработкой этой строки. Формат возвращает строку, даже если один из переданных ей аргументов объявлен как динамический ...
dynamic dynamicString = "d"; // just using a string here for simplicity, same problem occurs with any other type
string explicitString = string.Format("string is {0}", dynamicString); // works without issues
... кажется, что это невозможно сделать в следующем сценарии:
IEnumerable<string> strings = new[] { "a", "b", "c" };
IEnumerable<dynamic> dynamics = strings;
IEnumerable<string> output = dynamics.Select(d => string.Format("string is {0}", d)); // compiler error on this line
Компилятор жалуется:
"Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<dynamic>' to 'System.Collections.Generic.IEnumerable<string>'. An explicit conversion exists (are you missing a cast?)"
Поскольку компилятор должен иметь возможность делать вывод, что мое лямбда-выражение возвращает строку, я ожидал бы, что он также сделает вывод, что TResult для выбора должен иметь тип string (а не динамический).
Это было легко исправить, указав TSource и TResult явно следующим образом:
IEnumerable<string> output2 = dynamics.Select<dynamic, string>(d => string.Format("string is {0}", d)); // works !!!
Или я мог бы присвоить результат IEnumerable ...
IEnumerable<dynamic> output3 = dynamics.Select(d => string.Format("string is {0}", d)); // also works
Я также подтвердил, что эта проблема не возникает, когда я заменяю свой IEnumerable на IEnumerable :
IEnumerable<object> objects = strings;
IEnumerable<string> output4 = objects.Select(o => string.Format("string is {0}", o)); // works
И что интересно, даже следующие работы:
IEnumerable<string> output5 = dynamics.Select(d => string.Format("string is {0}", (object)d)); // works
IEnumerable<string> output6 = dynamics.Select(d => string.Format("string is {0}", (string)d)); // works
Кто-нибудь может объяснить, что здесь происходит? Это известное ограничение компилятора C # или я нашел еще одну ошибку?