为什么动态 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
.
的 特殊 行为
我正在使用 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
.