背景:我正在使用 Visual Basic 和 VS Community 2013。我正在制作一个 Windows 窗体应用程序。用例是:用户单击按钮。这会弹出一个对话框。然后 TCP 客户端连接到远程服务器,并等待来自服务器的消息到达。每次消息到达时,对话框上都会显示文本。如果远程端关闭套接字,则应关闭该对话框。此外,用户可以单击对话框上的按钮,该按钮应关闭套接字并关闭对话框。
我的代码似乎实现了除最后一个要求之外的所有这些。当用户单击按钮关闭对话框时,我会看到通常的异常弹出窗口,其中包含文本:
An exception of type 'System.AggregateException' occurred in mscorlib.dll but was not handled in user code.
Additional information: One or more errors occurred.
选择“Break”会显示条件 T.Result = 0
被突出显示。调试器显示 T
的值为 Id = 1,Status = Faulted {7},Method = "{null}",Result = "{Not YetComputed}"
我的问题是:此错误意味着什么以及如何修复它?
以下是对话框代码的相关部分。为了简洁起见,我省略了 ShowStatus
函数,它除了更新表单上的可视控件之外什么也不做。
Imports Microsoft.VisualBasic
Imports System.Net.Sockets
Imports System.Text
Public Class FormMyDialog
Private gRequest As String
Private inbuf(10000) As Byte
Private inoff As Integer
Private serv As NetworkStream
Private sock As System.Net.Sockets.TcpClient
' the main form calls this when the user clicks a button
Public Sub Go(request As String)
gRequest = request
ShowDialog()
End Sub
' this is the Close button I have placed on the dialog
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
sock.Close()
End Sub
Private Sub FormMyDialog_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
sock = New System.Net.Sockets.TcpClient()
ShowStatus("Connecting")
sock.Connect("127.0.0.1", 53000)
ShowStatus("Connected")
serv = sock.GetStream()
Dim outbuf As Byte() = Encoding.ASCII.GetBytes(gRequest + Chr(10))
serv.Write(outbuf, 0, outbuf.Length)
serv.Flush()
inoff = 0
ReadLoop()
End Sub
Private Sub ReadLoop()
Dim readlen As Integer
Dim T As Task(Of Integer)
T = serv.ReadAsync(inbuf, inoff, inbuf.Length - inoff)
If T.Result = 0 Then
sock.Close()
Dim d As MethodNoArgs(Of Object)
d = AddressOf Me.Close
Me.Invoke(d)
Return
End If
readlen = T.Result
inoff = inoff + readlen
ProcessInbuf()
T.ContinueWith(Sub() ReadLoop())
End Sub
Public Delegate Sub MethodNoArgs(Of T1)()
Private Sub ProcessInbuf()
' (omitted) processing that calls ShowStatus
' and updates inbuf and inoff
End Sub
End Class
最佳答案
您已经注意到,AggregateException
只是对发生的多个可能异常的包装。
我不太确定为什么这个函数会失败,但这可能是由代码的奇怪结构引起的。我看到的主要问题是您没有遵循干净的 async
-await
结构。通常,您不需要搞乱 ContinueWith
和 .Result
确实可以在这里得到您想要做的事情。
关键是使用await
关键字。该关键字基本上结合了 ContinueWith
和 .Result
。这意味着它会非阻塞地等待,直到异步操作完成并返回结果。
您的代码实际上可以归结为这样的内容:
Private Async Sub ReadLoop()
Dim readlen As Integer
Do
readlen = Await serv.ReadAsync(inbuf, inoff, inbuf.Length - inoff)
inoff = inoff + readlen
ProcessInbuf()
'maybe this should be async too, to wait until the processing is done
Loop While readlen > 0
sock.Close()
Me.Close()
End Sub
使用 Await
的另一个优点是它还可以解包 AggregateException
。您只需确保正确处理异常,因为 Async Sub
可能会因异常而终止,并且不会将异常返回到外部类。一旦通过第一个 Await
,就会发生这种情况。但是,一旦您的代码通过了 ContinueWith
,就会出现相同的“问题”。
关于vb.net - 使用 ReadAsync 时发生类型 'System.AggregateException' 的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34081152/