背景:我正在使用Visual Basic,VS社区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.
选择“中断”表示条件T.Result = 0
已突出显示。调试器显示T
的值为Id = 1, Status = Faulted {7}, Method = "{null}", Result = "{Not yet computed}"
我的问题是:这个错误意味着什么,我该如何解决?
以下是对话框代码的相关部分。为简洁起见,我省略了函数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
答案 0 :(得分:2)
您已经注意到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
。