如何在 VB.NET 中编写异步子程序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45870469/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 20:19:53  来源:igfitidea点击:

How to write an Async Sub in VB.NET?

vb.netasynchronousasync-await

提问by Andrew

Public Class LoginManager
    Implements ILoginManager
    Private ReadOnly _iLoginRepository As ILoginRepository
    Public Sub New()
        _iLoginRepository = New LoginRepository()
    End Sub

    Public Async Sub InsertFailedLoginAttempt(failedLoginAttempt As FailedLogin) Implements ILoginManager.InsertFailedLoginAttempt
        'Example of the S in Solid (Single Repsonsibilty)
        'Need to call these method async. But await errors 
            _iLoginRepository.InsertFailedLoginAttemptAsync(failedLoginAttempt)
            _iLoginRepository.InsertFailedLoginAttemptIntoLoginMasterAsync(failedLoginAttempt)
        End Sub
    End Class

Repsoitory Interface:

资源库接口:

Public Interface ILoginRepository
    Function IsUserAuthenticatedAsync(ByVal cID As String, ByVal password As String, ByVal IsExternalUser As Boolean) As Task(Of Boolean)
    Sub InsertFailedLoginAttemptAsync(ByVal failedLoginAttempt As FailedLogin)
    Sub InsertFailedLoginAttemptIntoLoginMasterAsync(ByVal failedLoginAttempt As FailedLogin)

End Interface

Repository Implementation:

存储库实现:

Public Class LoginRepository
    Implements ILoginRepository
    Public ReadOnly _applicationDBContext As New ApplicationDBContext()

    Public Async Sub InsertFailedLoginAttemptAsync(failedLoginAttempt As FailedLogin) Implements ILoginRepository.InsertFailedLoginAttemptAsync
        Using _applicationDBContext
            _applicationDBContext.RepFailedLogins.Add(failedLoginAttempt)
            Await _applicationDBContext.SaveChangesAsync()
        End Using
    End Sub

    Public Async Sub InsertFailedLoginAttemptIntoLoginMasterAsync(failedLoginAttempt As FailedLogin) Implements ILoginRepository.InsertFailedLoginAttemptIntoLoginMasterAsync
        Using _applicationDBContext
            _applicationDBContext.RepFailedLoginMasters.Add(failedLoginAttempt)
            Await _applicationDBContext.SaveChangesAsync()
        End Using
    End Sub

    ''' <summary>
    ''' Determine whether a user is authenticated, be it an internal or external user
    ''' I have condensed two methods into one
    ''' </summary>
    ''' <param name="cID"></param>
    ''' <param name="password"></param>
    ''' <param name="IsExternalUser"></param>
    ''' <returns></returns>
    Public Async Function IsUserAuthenticatedAsync(cID As String, password As String, IsExternalUser As Boolean) As Task(Of Boolean) Implements ILoginRepository.IsUserAuthenticatedAsync
        If (IsExternalUser And String.IsNullOrEmpty(password)) Then
            Throw New ArgumentNullException("External user requires password")
        End If

        Dim user As Chaser
        Dim toRet As Boolean

        Using _applicationDBContext
            'Two ways to use LINQ
            'First is LINQ Lambda sybntax(little harder to read)
            user = Await _applicationDBContext.Chasers.Where(Function(x) x.CID = cID).FirstOrDefaultAsync()

            'Second is LINQ Query syntax(looks more like SQL just more verbose
            'user = From x In _applicationDBContext.Chasers
            '       Where x.CID = cID
            '       Select x
        End Using

        If IsNothing(user) Then
            toRet = False
        ElseIf Not IsExternalUser And Not IsNothing(user) Then
            toRet = True
        ElseIf IsExternalUser And user.Hash_Password = password Then
            toRet = True
        End If

        Return toRet
    End Function
End Class

I'm trying to call the InsertFailedLoginAttemptAsyncrepository method in my manager. It is an async method but I am unable to await the method. How can I make this method awaitable?

我正在尝试InsertFailedLoginAttemptAsync在我的经理中调用存储库方法。这是一个异步方法,但我无法等待该方法。我怎样才能让这个方法等待?

I believe it has something to do with the interface and not making it an async method like in C# but I'm unable to do this.

我相信它与接口有关,而不是像 C# 那样使它成为异步方法,但我无法做到这一点。

回答by Nkosi

Subs should not be async. Event handlers are the only exception to that rule. You await Taskwhich can only be returned from a Function. If the intention is to make that interface async then all the members need to be functions that return a Taskor its derivative.

Subs 不应该是异步的。事件处理程序是该规则的唯一例外。您 awaitTask只能从Function. 如果目的是使该接口异步,则所有成员都需要是返回 aTask或其派生类的函数。

Async is something that bubbles all the way through when used. That said the ILoginManageralong with the ILoginRepositoryshould be refactored (if possible) to follow the proper syntax.

异步是在使用时一直冒泡的东西。也就是说ILoginManagerILoginRepository应该重构(如果可能)以遵循正确的语法。

Reference: Async/Await - Best Practices in Asynchronous Programming

参考:Async/Await - 异步编程的最佳实践

回答by Andrew

Fixed via Nkosi's reply:

通过 Nkosi 的回复修复:

Interface:

界面:

Public Interface ILoginRepository
    Function IsUserAuthenticatedAsync(ByVal cID As String, ByVal password As String, ByVal IsExternalUser As Boolean) As Task(Of Boolean)
    Function InsertFailedLoginAttemptAsync(ByVal failedLoginAttempt As FailedLogin) As Task
    Function InsertFailedLoginAttemptIntoLoginMasterAsync(ByVal failedLoginAttempt As FailedLogin) As Task

End Interface

Manager method:

管理员方法:

 Public Async Function InsertFailedLoginAttempt(failedLoginAttempt As FailedLogin) As Task Implements ILoginManager.InsertFailedLoginAttempt
        'Example of the S in Solid (Single Repsonsibilty)
        Await _iLoginRepository.InsertFailedLoginAttemptAsync(failedLoginAttempt)
        Await _iLoginRepository.InsertFailedLoginAttemptIntoLoginMasterAsync(failedLoginAttempt)
    End Function