VB.NET中的异步Lambda表达式

3
像这样的异步Sub:
Dim f As Func(Of Task) = Async Sub()
                         End Sub

产生编译错误:

错误 BC36670: 嵌套的子程序没有与委托 'System.Func(Of System.Threading.Tasks.Task)' 兼容的签名。

等效的 C# 代码可以编译通过:

Func<Task> f = async () => { };

Async Sub 重写为 Async Function 可以使代码正常运行。

为什么 Async Sub() 不能转换为返回类型为 Task 的委托类型?

1个回答

4

VB.NET中的Sub相当于C#中的void。在async void Foo() {}async Task Foo() {}之间有区别,而您的VB.NET正在执行前者,而您需要后者。正如您提到的,Async Function可以使其正常工作,因为它实际上执行了后者。

编辑:一些更多的细节:

C#:

async void Foo() { }

async Task Bar() { }

void Baz()
{
    object dummy;
    dummy = (Action) Foo; // OK
    dummy = (Func<Task>) Foo; // error
    dummy = (Action) Bar; // error
    dummy = (Func<Task>) Bar; // OK
}

然而,当使用委托时会变得更加混乱,因为 FooBar 的代理等价物看起来相同:async () => { }
唯一的区别在于,在VB.NET中,委托看起来并不相同,因为 SubFunction 关键字仍然是语法的一部分。

VB.NET中的“Function”实际上意味着从方法中返回某个值。在上面的代码中没有返回值,因此lambda-“Function”实际上应该是lambda-“Sub”。你是否曾经看到过在VB.NET中没有“Return”语句的“Function”? - controlflow
@ControlFlow C#的等价物确实会返回一个值,而且这个值是一个“Task”。该任务的返回是隐式的:您没有“return”语句,但确实返回了某些内容。在VB.NET中也是一样的。 - user743382
1
@hvd 我认为问题在于,虽然 C# 的 async 关键字将 void 函数的声明转换为 Func<Task>,但在 VB.NET 中,Async 似乎不会Sub 的声明转换为相同的东西。请注意,在 C# 示例中,我们可以使用 () => {}(它不返回任何内容,因此对应于 VB.NET 的 Sub)并通过在前面添加 async 将其分配给 Func<Task> - 类似的过程似乎适用于 VB.NET。我想这就是问题所在。 - AakashM
2
@AakashM 是的,没错。在返回 Task<T> 的异步函数中,你不会返回一个 Task<T>,而是返回一个 Tasync Task<int> Foo() { return 1; } - user743382
3
在C#中考虑枚举器:当您说IEnumerable<int> M() { yield return 1; }时,您不会返回任何内容,但会yield一个整数。您不会返回一系列整数--您没有返回任何东西--而是生成一个整数序列。编译器会处理重写为返回IEnumerable<int>的方法。异步方法也是这样。如果异步方法返回一个Task<int>,那么您将返回一个整数,而编译器将其转换为返回Task<int>的方法。 - Eric Lippert
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接