如何使用 CallByName 或调用 Async/Await

How do I use CallByName or Invoke with Async/Await

CallByName 和 Invoke 不是异步函数,所以我不能使用如下明显的语法异步调用它们:

rv = await CallByName(objScripts, txtScript.Text, CallType.Method)

显然我是唯一需要这个的人,所以互联网上没有答案。

我的用例是我有数百个用 vb.net 编写的数据库转换脚本。我有一个数据库,其中脚本处理哪个数据库。然后我的代码读取数据库并在更新的数据库到达时处理每个脚本,或者我可以 select 我的 UI 和 运行 下拉列表中的脚本那样。

我现在需要 运行 一些这些脚本异步,这样我就可以使用 PuppeteerSharp 来抓取一些数据,而不是使用数据库。

那么我该怎么做呢?

好的,明白了。

Private Async Function RunAScript_Worker(ScriptName As String, objScript As Object) As Task(Of Integer)

    Try
        Dim result As Task(Of Integer) = CType(objScript.GetType().GetMethod(ScriptName).Invoke(objScript, Nothing), Task(Of Integer))
        Await result
        Return result.Result
    Catch ex As Exception
        Throw ex
    End Try

End Function

你这样称呼它:

rv = Await RunAScript_Worker(ScriptName, ClsContainingMethod)

这使用反射和 .Invoke 并通过添加 Task(Of Integer) 类型将其变成可等待的方法。

您还需要为被调用的方法添加 Async,但您可以保留不需要的方法,它会正常工作。

编辑:

嗯,差不多了。当我尝试 return 来自未设置为异步的其他函数的值时,问题就出现了。 await 需要一个任务(整数),但 non-async 函数 return 只是整数,我得到一个 运行 时间错误。

所以我想出了如何使用反射来确定该方法是否是异步的。我发现 GetMethod() 中的名称参数是区分大小写的,因此出于这个原因和其他原因,我在执行该方法之前添加了检查。我也比我的更喜欢@Charlieface 的解决方案,所以:

If Not objScripts.GetType().GetMethod(ScriptName) Is Nothing Then
    If objScripts.GetType().GetMethod(ScriptName).ReturnTypeCustomAttributes.ToString.Contains("Task") Then
        Return Await DirectCast(CallByName(objScripts, ScriptName, CallType.Method), Task(Of Integer))
    Else
        Return CallByName(objScripts, ScriptName, CallType.Method)
    End If
Else
    ' Exception handling
End If

只需将结果转换为 Taskawait

rv = Await DirectCast(CallByName(objScripts, txtScript.Text, CallType.Method), Task)