为什么动态 IEnumerable 上的 First() 或 ElementAt() 是可等待的?

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

我正在使用 Dapper 并将其 return 动态 IEnumerable,如下所示:

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

这里,rows的类型是IEnumerable<dynamic>。 IntelliSense 表示 FirstOrDefault() 是可等待的,并且具有用法 await FirstOrDefault()。并非所有 LINQ 查询都显示为可等待,但似乎尤其是那些以某种方式挑出元素的查询。

只要我改用强类型,这种行为就会消失。

是否因为 .NET 无法知道您在运行时接收到的类型是否可等待,所以它 "allows" 它以备不时之需?但是不强制执行?或者,由于某些动态语言运行时行为,我应该在这里实际使用 await 吗?

我一直在搜索,但没有在网上找到关于此的最小信息。

async-await 编译器的特性取决于 Duck Typing。所以所有具有方法 GetAwaiter(实例或扩展方法)的东西 returns 类型实现 INotifyCompletion 接口并具有下一个字段:

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

敬请期待

你可以在编译时调用任何你想要的动态类型(来自docs):

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

这就是编译器在编译时不显示任何 warnings/errors 的原因,但在运行时你会得到类似于以下的异常:

RuntimeBinderException.

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

如果您明确指定类型,编译器将搜索方法 GetAwaiter。然后如果你的强类型不包含它你会得到编译时错误。

因此,您问题的答案确实是因为 dynamic.

特殊 行为