Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 如何优雅地完成拥有线程并引发事件的对象?_.net_Multithreading_Thread Safety_.net 2.0 - Fatal编程技术网

.net 如何优雅地完成拥有线程并引发事件的对象?

.net 如何优雅地完成拥有线程并引发事件的对象?,.net,multithreading,thread-safety,.net-2.0,.net,Multithreading,Thread Safety,.net 2.0,问题是当调用方忘记处理我的对象时该怎么办。因此,为了简洁起见,我跳过了实现IDisposable。我的问题是:最后一个代码示例有多危险?可以改进吗?或者我太沉迷于优雅了?或者也许有另一种模式可以更好地做到这一点 故事的开头是试图包装一些长时间运行的进程,以便可以从主线程安全地访问它 Public Class ThisCantRaiseEvents Private client As UdpClient Public Sub New(ByVal client As UdpClie

问题是当调用方忘记处理我的对象时该怎么办。因此,为了简洁起见,我跳过了实现
IDisposable
。我的问题是:最后一个代码示例有多危险?可以改进吗?或者我太沉迷于优雅了?或者也许有另一种模式可以更好地做到这一点

故事的开头是试图包装一些长时间运行的进程,以便可以从主线程安全地访问它

Public Class ThisCantRaiseEvents
    Private client As UdpClient

    Public Sub New(ByVal client As UdpClient)
        Me.client = client
        Dim thread As New Thread(AddressOf DoWork)
        thread.IsBackground = True
        thread.Start(client)
    End Sub

    Public Event PacketReceived As EventHandler

    Protected Overrides Sub Finalize()
        client.Close()
    End Sub

    Private Shared Sub DoWork(ByVal state As Object)
        Dim client As UdpClient = DirectCast(state, UdpClient)
        Try
            While True
                client.Receive(Nothing)
            End While
        Catch ex As Exception
        End Try
    End Sub
End Class
将事件分派到主线程的天真尝试。工作正常,但从不超出范围,因为它自己的线程使其保持活动状态。(请记住,如果线程对象超出范围,线程不会死亡。)

“这是我第一次尝试解决上一个示例中的问题。唉,随着嫁妆方法变得越来越复杂,它很快变得非常丑陋

Public Class ThisIsVeryUgly
    Private client As UdpClient
    Private mainThread As Control

    Public Sub New(ByVal client As UdpClient, ByVal control As Control)
        Me.client = client
        Me.mainThread = control
        Dim thread As New Thread(AddressOf DoWork)
        thread.IsBackground = True
        thread.Start(New WeakReference(Me))
    End Sub

    Public Event PacketReceived As EventHandler

    Protected Overrides Sub Finalize()
        client.Close()
    End Sub

    Protected Overridable Sub OnPacketReceived(ByVal e As EventArgs)
        RaiseEvent PacketReceived(Me, e)
    End Sub

    Private Shared Sub DoWork(ByVal state As Object)
        Dim weakThis As WeakReference = DirectCast(state, WeakReference)
        Dim this As ThisIsVeryUgly = DirectCast(weakThis.Target, ThisIsVeryUgly)
        Dim client As UdpClient = this.client
        this = Nothing
        Try
            While True
                client.Receive(Nothing)
                this = DirectCast(weakThis.Target, ThisIsVeryUgly)
                this.mainThread.BeginInvoke(New Action(Of EventArgs) _
                (AddressOf this.OnPacketReceived), EventArgs.Empty)
                this = Nothing
                ' Repeat for every other place we need to raise an event! Ugh!
            End While
        Catch ex As Exception
        End Try
    End Sub
End Class
这是我的最新发明。它很优雅,但可能会引起问题,因为它引发的事件的
sender
参数不是用户所期望的这会给我带来任何问题吗?

Public Class ThisIsAlmostGood
    Private client As UdpClient
    Private worker As WorkThread

    Public Sub New(ByVal client As UdpClient, ByVal mainThread As Control)
        Me.client = client
        worker = New WorkThread(client, mainThread)
    End Sub

    Public Custom Event PacketReceived As EventHandler
        AddHandler(ByVal value As EventHandler)
            AddHandler worker.PacketReceived
        End AddHandler
        RemoveHandler(ByVal value As EventHandler)
            RemoveHandler worker.PacketReceived
        End RemoveHandler
        RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)
        End RaiseEvent
    End Event

    Protected Overrides Sub Finalize()
        client.Close()
    End Sub

    Private Class WorkThread
        Private client As UdpClient
        Private mainThread As Control

        Public Sub New(ByVal client As UdpClient, ByVal mainThread As Control)
            Me.client = client
            Me.mainThread = mainThread
            Dim thread As New Thread(AddressOf DoWork)
            thread.IsBackground = True
            thread.Start()
        End Sub

        Public Event PacketReceived As EventHandler

        Protected Overridable Sub OnPacketReceived(ByVal e As EventArgs)
            ' But the user expects a pointer to ThisIsAlmostGood,
            ' not WorkThread! Should I pass Nothing instead?
            RaiseEvent PacketReceived(Me, e)
        End Sub

        Private Sub DoWork(ByVal state As Object)
            Try
                While True
                    client.Receive(Nothing)
                    mainThread.BeginInvoke(New Action(Of EventArgs) _
                    (AddressOf OnPacketReceived), EventArgs.Empty)
                End While
            Catch ex As Exception
            End Try
        End Sub
    End Class
End Class

您发布了大量代码。如果你能用一个简单的代码示例来总结这一点,你将更有可能得到好的答案。这已经是我在不丢失上下文的情况下能想到的最少的代码了。只有一条注释。这个代码是做什么的?它可以实现为WCF服务吗?它在接收到数据包时触发事件。但这与问题无关。这段代码只是我问题的一个例子。举个例子。这不是真正的代码。
Public Class ThisIsAlmostGood
    Private client As UdpClient
    Private worker As WorkThread

    Public Sub New(ByVal client As UdpClient, ByVal mainThread As Control)
        Me.client = client
        worker = New WorkThread(client, mainThread)
    End Sub

    Public Custom Event PacketReceived As EventHandler
        AddHandler(ByVal value As EventHandler)
            AddHandler worker.PacketReceived
        End AddHandler
        RemoveHandler(ByVal value As EventHandler)
            RemoveHandler worker.PacketReceived
        End RemoveHandler
        RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)
        End RaiseEvent
    End Event

    Protected Overrides Sub Finalize()
        client.Close()
    End Sub

    Private Class WorkThread
        Private client As UdpClient
        Private mainThread As Control

        Public Sub New(ByVal client As UdpClient, ByVal mainThread As Control)
            Me.client = client
            Me.mainThread = mainThread
            Dim thread As New Thread(AddressOf DoWork)
            thread.IsBackground = True
            thread.Start()
        End Sub

        Public Event PacketReceived As EventHandler

        Protected Overridable Sub OnPacketReceived(ByVal e As EventArgs)
            ' But the user expects a pointer to ThisIsAlmostGood,
            ' not WorkThread! Should I pass Nothing instead?
            RaiseEvent PacketReceived(Me, e)
        End Sub

        Private Sub DoWork(ByVal state As Object)
            Try
                While True
                    client.Receive(Nothing)
                    mainThread.BeginInvoke(New Action(Of EventArgs) _
                    (AddressOf OnPacketReceived), EventArgs.Empty)
                End While
            Catch ex As Exception
            End Try
        End Sub
    End Class
End Class