【发布时间】:2020-10-25 06:58:08
【问题描述】:
这在 C# 中可能吗?以下代码会产生编译器错误。
HashSet<Task<(string Value, int ToNodeId)>> regionTasks =
new HashSet<Task<(string Value, int ToNodeId)>>();
foreach (Connection connection in Connections[RegionName])
{
regionTasks.Add(async () =>
{
string value = await connection.GetValueAsync(Key);
return (value, connection.ToNode.Id);
}());
}
C# 编译器报错,“错误 CS0149:需要方法名称。”它无法推断 lambda 方法的返回类型。
请注意我在 lambda 块关闭 {} 后立即通过 () 调用 lambda 方法的技术。这可确保返回 Task,而不是 Func。
VB.NET 编译器理解这种语法。我惊讶地发现 VB.NET 编译器比 C# 编译器更聪明。请参阅我的 An Async Lambda Compiler Error Where VB Outsmarts C# 博客文章了解完整故事。
Dim regionTasks = New HashSet(Of Task(Of (Value As String, ToNodeId As Integer)))
For Each connection In Connections(RegionName)
regionTasks.Add(Async Function()
Dim value = Await connection.GetValueAsync(Key)
Return (value, connection.ToNode.Id)
End Function())
Next
VB.NET 编译器理解End Function() 技术。它正确地推断出 lambda 方法的返回类型是 Function() As Task(Of (Value As String, ToNodeId As Integer)),因此调用它会返回 Task(Of (Value As String, ToNodeId As Integer))。这可以分配给regionTasks 变量。
C# 要求我将 lambda 方法的返回值转换为 Func,这会产生非常难以辨认的代码。
regionTasks.Add(((Func<Task<(string Values, int ToNodeId)>>)(async () =>
{
string value = await connection.GetValueAsync(Key);
return (value, connection.ToNode.Id);
}))());
太糟糕了。括号太多!我在 C# 中能做的最好的事情就是显式声明 Func,然后立即调用它。
Func<Task<(string Value, int ToNodeId)>> getValueAndToNodeIdAsync = async () =>
{
string value = await connection.GetValueAsync(Key);
return (value, connection.ToNode.Id);
};
regionTasks.Add(getValueAndToNodeIdAsync());
有没有人找到更优雅的解决方案?
【问题讨论】:
-
IIFE 风格的问题在于编译器还没有确定它是表达式树还是匿名方法。有时很烦人,但很少遇到。
-
这阐明了为什么 C# 编译器无法推断返回类型。虽然我仍然很困惑为什么 VB.NET 编译器可以。我想我需要阅读 .NET 表达式树。
-
确实很奇怪。我希望 VB 假定它是一个匿名方法。如果是这样,一个实际的选择。
-
@ErikMadsen 似乎表达树are not related 的问题。
-
@GuruStron 我不这么认为。我声明了 regionTasks 变量的类型。提问者表示他的代码的强类型版本确实可以编译。他只遇到了 var 类型版本的编译器错误。
标签: c# vb.net asynchronous task anonymous-function