Is this possible in C#? The following code produces a compiler error.
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);
}());
}
The C# compiler complains, "Error CS0149: Method name expected." It's unable to infer the lambda method's return type.
Note my technique of invoking the lambda method immediately via the () after the the lambda block is closed {}. This ensures a Task
is returned, not a Func
.
The VB.NET compiler understands this syntax. I am stunned to find an example of the VB.NET compiler outsmarting the C# compiler. See my An Async Lambda Compiler Error Where VB Outsmarts C# blog post for the full story.
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
The VB.NET compiler understands the End Function()
technique. It correctly infers the lambda method's return type is Function() As Task(Of (Value As String, ToNodeId As Integer))
and therefore invoking it returns a Task(Of (Value As String, ToNodeId As Integer))
. This is assignable to the regionTasks
variable.
C# requires me to cast the lambda method's return value as a Func
, which produces horribly illegible code.
regionTasks.Add(((Func<Task<(string Values, int ToNodeId)>>)(async () =>
{
string value = await connection.GetValueAsync(Key);
return (value, connection.ToNode.Id);
}))());
Terrible. Too many parentheses! The best I can do in C# is explicitly declare a Func
, then invoke it immediately.
Func<Task<(string Value, int ToNodeId)>> getValueAndToNodeIdAsync = async () =>
{
string value = await connection.GetValueAsync(Key);
return (value, connection.ToNode.Id);
};
regionTasks.Add(getValueAndToNodeIdAsync());
Has anyone found a more elegant solution?