Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is First() or ElementAt() on a dynamic IEnumerable awaitable?

I was using Dapper and having it return a dynamic IEnumerable, like this:

var rows = conn.Query("SELECT * FROM T WHERE ID = @id", new { id = tableId });
var row = rows.FirstOrDefault();

Here, rows is of type IEnumerable<dynamic>. The IntelliSense says FirstOrDefault() is awaitable, and has the usage await FirstOrDefault(). Not all LINQ queries are shown as awaitable, but it seems like especially those that somehow single out elements are.

As soon as I instead use strong typing, this behavior goes away.

Is it because .NET can't know if the type you are receiving at runtime is awaitable or not, so that it "allows" it, in case you need it? But doesn't enforce it? Or am I supposed to, due to some Dynamic Language Runtime behavior, actually use await here?

I have kept searching but not found the smallest thing about this online.

like image 811
Jonas Avatar asked Oct 09 '15 09:10

Jonas


1 Answers

async-await feature of compiler depends on Duck Typing. So everything that has method GetAwaiter (either instance or extension method) which returns type that implements INotifyCompletion interface and has the next fields:

  • bool IsCompleted { get; }
  • void|TResult GetResult()

can be awaited.

You can call whatever you want on dynamic type at compile time (from docs):

At compile time, an element that is typed as dynamic is assumed to support any operation.

That is why compiler does not show any warnings/errors at compile time, but at runtime you will get an exception similar to the following:

RuntimeBinderException.

'<>f__AnonymousType0' does not contain a definition for 'GetAwaiter'

If you specify type explicitly compiler will search for method GetAwaiter. Then if your strong type does not contain it you will get compile time error.

So, the answer to your question is that indeed that's because of special behavior of dynamic.

like image 51
xZ6a33YaYEfmv Avatar answered Nov 08 '22 13:11

xZ6a33YaYEfmv