Search code examples
c#visual-studiolinqyield-return

Why does Visual Studio think my "yield return" method returns a dynamic object?


I've written a method that returns an IEnumerable<T> using yield return like so:

public IEnumerable<Row> ConvertExcelToRows(IExcelDataReader reader)
{
    while (reader.Read())
    {
        var row = new Row();
        // do some work. No dynamic objects here whatsoever
        yield return row;
    }
}

When I consume my method and follow it with LINQ extension methods, Visual Studio shows the return value to be of type dynamic:

enter image description here

Here is the relevant code leading up to the symptom:

dynamic data = JsonConvert.DeserializeObject(jsonContent);
using (var stream = await DownloadFile(data.docUrl.ToString()))
using (var excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream))
{
    var rows = ConvertExcelToRows(excelReader).ToList<Row>();
}

The type of rows in the screen shot above is dynamic when it should be List<Row>.

Why is this happening and how can I fix it?

(Please note that Row is just a class I wrote up. It's all primitive properties, nothing dynamic)

KEY UPDATE: In the process of improving the screenshot above, I've changed the declaration of excelReader from var to IExcelDataReader. This solved my problem.

When I changed back to var, I saw that the inferred type of excelReader is indeed the contagious dynamic.

Would still love an explanation of why a dynamic input argument to my method would "infect" the type of the output.


Solution

  • dynamic operates by a contagion principle. If anything coming into an expression is dynamic, then the compiler can make no guarantees at compile time about what might come out -- so what comes out is considered dynamic as well. There's a limit to the static analysis a compiler can do when types may change arbitrarily at runtime.

    Therefore, if what's coming out of your expression is dynamic and you didn't assign the result to an explicitly dynamic variable, then that's because something dynamic must have come in. If you didn't give this method call anything explicitly dynamic, then something you gave it must have been "infected" elsewhere.

    Something upstream, a parameter to a method, the object you called the method on, or a term in an expression, is dynamic. You need to find out what.

    An obvious candidate is excelReader: Where did it come from, and where did that object come from? What were the parameters (if any) you gave the method, and where did you get them?

    Patient Zero is out there somewhere.