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.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With