VB.NET中Task.ContinueWith异常结果及委托使用疑问解析
Dim d = 1 Dim task1 = Task.Delay(1) Dim task2 = Task.Delay(2) Dim task4 = Sub() d += 1 'task4类型为委托Sub Dim task3 = task1.ContinueWith(task2) '报错 Dim task5 = task1.ContinueWith(Sub() d += 1) '正常运行 Dim task6 = task1.ContinueWith(task4) '报错 Dim task7 = task1.ContinueWith(New Action(Of Task)(task2)) '报错 Dim task8 = task1.ContinueWith(New Action(Of Task)(Function() task2)) '可编译,原理不明
疑问解答
直接传入task2为何报错?
ContinueWith要求传入的是可执行的委托类型(比如Action(Of Task)),而task2是已经创建好的Task实例,不是委托。它代表的是一个已存在的异步任务,不是“task1完成后要执行的代码逻辑”,类型不匹配所以报错。无参数Lambda Sub可适配接收Action(Of Task)的ContinueWith,原因是什么?
VB.NET有委托类型推断和参数省略的语法糖。当你写无参数的Sub() d +=1时,编译器会自动推断这个Lambda可以适配Action(Of Task)——它会自动给Lambda补上一个未被使用的Task参数(也就是ContinueWith会传入的前置完成任务实例),等效于你写了Sub(t As Task) d +=1,因此能匹配上ContinueWith的重载。task4与task5中Lambda类型相同,为何传入task4报错?
task4被明确声明为无参数的Action委托,类型已经固定;而task5的Lambda是在调用ContinueWith的瞬间由编译器做类型推断,自动补全了Task参数,适配成了Action(Of Task)。固定类型的无参数Action无法自动转换为带参数的Action(Of Task),所以传入task4会报错。task8用Function包裹task2可编译,而task7不行,原理是什么?
- task7错误原因:
task2是Task实例,不是委托,而Action(Of Task)是接收Task参数、无返回值的委托,两者类型完全不兼容,自然无法转换。 - task8可编译原因:
Function() task2是一个无参数、返回Task的Func(Of Task),VB.NET允许将这种无参数委托适配成带参数的Action(Of Task)——编译器会忽略传入的Task参数,执行这个Func并丢弃返回值(也就是创建并启动task2)。但注意:这种写法逻辑有问题,ContinueWith返回的Task会在task2创建后就结束,不会等待task2执行完成。
- task7错误原因:
Action(Of In T)无构造函数定义,其语法含义是什么?
Action(Of In T)是.NET框架定义的泛型委托类型,它本身是有构造函数的,你觉得没有是因为VB.NET的语法糖让你无需显式调用构造函数。其中:Action表示这是一个无返回值的委托;Of In T中的In表示这个泛型参数是逆变的——即可以用更宽泛的类型(比如Object)代替更具体的类型(比如String)作为委托的输入参数,提升委托的兼容性。
内容的提问来源于stack exchange,提问作者user4951

