none
Daten an mehrere Instanzen einer Klasse weitergeben RRS feed

  • Frage

  • Ich habe eine Klasse – nennen wir sie ‚Analyzer’, die Daten über die serielle Schnittstelle empfängt und aufbereitet.

     

    Nun habe ich eine weitere Klasse – nennen wir sie ‚ModulMX’, die die Daten  weiter verarbeiten soll.

     

    Wie der Name ModulMX suggeriert können mehrere Instanzen von ModulMX erzeugt werden.

     

    Die klasse ModulMX instanziiert wiederum die Klasse Analyzer und zwar in sog. ‚Singleton’-Technik um zu erreichen, das jeweils nur EINE einzige Instanz von Analyzer existiert. Seit ich diese technik anwende sind alle Probleme, im Zusammenhang mit dem Zugriff auf die serielle Schnittstelle von mehreren Instanzen aus verschwunden.

    Vielen Dank an dieser Stelle für den Hinweis auf Singleton und die Umsetzung.

     

    Über 2 privat deklarierte Variablen soll erreicht werden, dass sich jede instanz von ModulMX nur für bestimmte Daten von Analyzer interessiert.

    Jetzt stellt sich allerdings die Aufgabe, dass ‚Anaylzer’ alle Instanzen von ModulMX über den Eingang neuer Daten informieren muss:

     

    So geht’s NICHT:

    Analyzer ruft über ModulMX.ProcessNewData eine Sub innerhlab der Klasse ModulMX auf. Das führt zu einer Fehlermeldung, dass der zugriff nur über eine explizite Instanz möglich sei – eigentlich logisch.

     

    Idee 1:  Ich durchlaufe in einer Schleife alle existierneden Instanzen von ModulMX und rufe jeweils  ProcessNewData auf. Aber wie komme ich an eine Aufzählung der Instanzen ?

     

    Idee 2:

    Ich  definiere ein Ereignis in Anaylzer, z.B. Event NeueDatenEingetroffen(Data as IRGENDWAS) und erstelle die Instanz auf Analyzer  in ModulMX als Dim Withevents xxx as Analyzer.GetInstance.

     

    Beisst sich das mit der Singleton-Geschichte ? Würde dann tatsächlich JEDE  Instanz von ModulMX einen Ereignisaufruf von NeueDatenEingetroffen erhalten ?

     

    Oder bin ich völlig auf dem Holzweg und es geht ganz anders ?

     

    Gruss Nico

    Donnerstag, 9. Dezember 2010 12:12

Antworten

  • Hallo Nico,

    für Dein Vorhaben sind Ereignisse ideal.
    Und sie decken indirekt auch Deine Idee 1 ab.
    Denn intern verwalten Delegaten/Ereignisse eben jene Liste nach der Du suchst.
    Denn jeder Abbonnent, der AddHandler aufruft, trägt sich dabei in eine Aufrufliste ein.
    Und mit RemoveHandler entfernt man sich aus der Liste.

    ModuleMX kann sich beim Ereignis einklinken und wenn es aufgelöst wird,
    so meldet es sich ab. Üblicherweise verwendet man dafür das Dispose Muster.

    Dazu ein klein wenig Beispielcode:

    Public Class AnalyzerTest
      ' Ein kleiner Funktionstest
      Public Shared Sub Run()
        Dim m1 As New ModulMX("Module 1")
        Analyzer.Instance.Receive()
    
        Dim m2 As New ModulMX("Module 2")
        Analyzer.Instance.Receive()
    
        ' erste Freigeben
        m1.Dispose()
        Dim m3 As New ModulMX("Module 3")
        Analyzer.Instance.Receive()
      End Sub
    
    End Class
    
    
    Public Class Analyzer
      Private Shared ReadOnly __Instance As Analyzer = New Analyzer()
    
      Private Sub New()
      End Sub
    
      Public Shared ReadOnly Property Instance() As Analyzer
        Get
          Return __Instance
        End Get
      End Property
    
      ' Ereignis, dass beim Empfang von Daten ausgelöst wird.
      Public Event AnalyzerDataReceived As EventHandler(Of AnalyzerdataEventArgs)
    
      Private _receiveCount As Integer
    
      ' Eine Methoe die das Ereignis auslöst
      Public Sub Receive()
        ' Anzahl der Aufrufe (hier als Ereignisargumente
        Me._receiveCount += 1
    
        ' Löst das Ereignis aus
        RaiseEvent AnalyzerDataReceived(Me, New AnalyzerdataEventArgs(Me._receiveCount, "abc"))
      End Sub
    
    End Class
    
    Public Class AnalyzerdataEventArgs
      Inherits EventArgs
    
      Public Sub New(ByVal data1 As Integer, ByVal data2 As String)
        Me._data1 = data1
        Me._data2 = data2
      End Sub
    
      ' Irgendwelche data
      Private _data1 As Integer
      Public ReadOnly Property Data1 As Integer
        Get
          Return Me._data1
        End Get
      End Property
    
      Private _data2 As String
      Public ReadOnly Property Data2 As String
        Get
          Return Me._data2
        End Get
      End Property
    End Class
    
    Public Class ModulMX
      Implements IDisposable
      Private _name As String ' Zur Identifikation
    
      Public Sub New(ByVal name As String)
        Me._name = name
    
        AddHandler Analyzer.Instance.AnalyzerDataReceived, AddressOf AnalyzerDataReceived
      End Sub
    
    #Region "IDisposable Schnittstelle"
    
      Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
      End Sub
    
      Private _disposed As Boolean
      Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me._disposed AndAlso disposing Then
          RemoveHandler Analyzer.Instance.AnalyzerDataReceived, AddressOf AnalyzerDataReceived
        End If
        Me._disposed = True
      End Sub
    #End Region
    
      Private Sub AnalyzerDataReceived(ByVal sender As Object, ByVal e As AnalyzerdataEventArgs)
        ' Empfangene Daten anzeigen...
        Console.WriteLine("Data Received: {0}: {1} - {2}", Me._name, e.Data1, e.Data2)
      End Sub
    End Class
    

    Die Klasse AnalyzerTest dient zur Illustration der Funktionsweise und wäre mit AnalyzerTest.Run aufzurufen
    um zu zeigen, dass die Ereignisse ankommen.

    P.S.: ModulMX finde ich für einen Klassennamen nicht ideal, weil VB ein Module kennt,
    was einen anderen (hier widersprechenden) Hintergrund hat.

    Gruß Elmar

    Donnerstag, 9. Dezember 2010 13:10
    Beantworter
  • hallo Nico,

    prinzipiell hast du die richtige Idee schon, Idee 2. Du brauchst im Grunde einen Event Broker, z.b.:

    http://msforge.net/blogs/paki/archive/2007/11/14/simple-eventbroker-implementation-in-c.aspx

    http://msforge.net/blogs/paki/archive/2007/11/20/EventBroker-implementation-in-C_2300_-full-source-code.aspx


    Microsoft MVP Office Access
    https://mvp.support.microsoft.com/profile/Stefan.Hoffmann
    Donnerstag, 9. Dezember 2010 13:03

Alle Antworten

  • hallo Nico,

    prinzipiell hast du die richtige Idee schon, Idee 2. Du brauchst im Grunde einen Event Broker, z.b.:

    http://msforge.net/blogs/paki/archive/2007/11/14/simple-eventbroker-implementation-in-c.aspx

    http://msforge.net/blogs/paki/archive/2007/11/20/EventBroker-implementation-in-C_2300_-full-source-code.aspx


    Microsoft MVP Office Access
    https://mvp.support.microsoft.com/profile/Stefan.Hoffmann
    Donnerstag, 9. Dezember 2010 13:03
  • Hallo Nico,

    für Dein Vorhaben sind Ereignisse ideal.
    Und sie decken indirekt auch Deine Idee 1 ab.
    Denn intern verwalten Delegaten/Ereignisse eben jene Liste nach der Du suchst.
    Denn jeder Abbonnent, der AddHandler aufruft, trägt sich dabei in eine Aufrufliste ein.
    Und mit RemoveHandler entfernt man sich aus der Liste.

    ModuleMX kann sich beim Ereignis einklinken und wenn es aufgelöst wird,
    so meldet es sich ab. Üblicherweise verwendet man dafür das Dispose Muster.

    Dazu ein klein wenig Beispielcode:

    Public Class AnalyzerTest
      ' Ein kleiner Funktionstest
      Public Shared Sub Run()
        Dim m1 As New ModulMX("Module 1")
        Analyzer.Instance.Receive()
    
        Dim m2 As New ModulMX("Module 2")
        Analyzer.Instance.Receive()
    
        ' erste Freigeben
        m1.Dispose()
        Dim m3 As New ModulMX("Module 3")
        Analyzer.Instance.Receive()
      End Sub
    
    End Class
    
    
    Public Class Analyzer
      Private Shared ReadOnly __Instance As Analyzer = New Analyzer()
    
      Private Sub New()
      End Sub
    
      Public Shared ReadOnly Property Instance() As Analyzer
        Get
          Return __Instance
        End Get
      End Property
    
      ' Ereignis, dass beim Empfang von Daten ausgelöst wird.
      Public Event AnalyzerDataReceived As EventHandler(Of AnalyzerdataEventArgs)
    
      Private _receiveCount As Integer
    
      ' Eine Methoe die das Ereignis auslöst
      Public Sub Receive()
        ' Anzahl der Aufrufe (hier als Ereignisargumente
        Me._receiveCount += 1
    
        ' Löst das Ereignis aus
        RaiseEvent AnalyzerDataReceived(Me, New AnalyzerdataEventArgs(Me._receiveCount, "abc"))
      End Sub
    
    End Class
    
    Public Class AnalyzerdataEventArgs
      Inherits EventArgs
    
      Public Sub New(ByVal data1 As Integer, ByVal data2 As String)
        Me._data1 = data1
        Me._data2 = data2
      End Sub
    
      ' Irgendwelche data
      Private _data1 As Integer
      Public ReadOnly Property Data1 As Integer
        Get
          Return Me._data1
        End Get
      End Property
    
      Private _data2 As String
      Public ReadOnly Property Data2 As String
        Get
          Return Me._data2
        End Get
      End Property
    End Class
    
    Public Class ModulMX
      Implements IDisposable
      Private _name As String ' Zur Identifikation
    
      Public Sub New(ByVal name As String)
        Me._name = name
    
        AddHandler Analyzer.Instance.AnalyzerDataReceived, AddressOf AnalyzerDataReceived
      End Sub
    
    #Region "IDisposable Schnittstelle"
    
      Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
      End Sub
    
      Private _disposed As Boolean
      Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me._disposed AndAlso disposing Then
          RemoveHandler Analyzer.Instance.AnalyzerDataReceived, AddressOf AnalyzerDataReceived
        End If
        Me._disposed = True
      End Sub
    #End Region
    
      Private Sub AnalyzerDataReceived(ByVal sender As Object, ByVal e As AnalyzerdataEventArgs)
        ' Empfangene Daten anzeigen...
        Console.WriteLine("Data Received: {0}: {1} - {2}", Me._name, e.Data1, e.Data2)
      End Sub
    End Class
    

    Die Klasse AnalyzerTest dient zur Illustration der Funktionsweise und wäre mit AnalyzerTest.Run aufzurufen
    um zu zeigen, dass die Ereignisse ankommen.

    P.S.: ModulMX finde ich für einen Klassennamen nicht ideal, weil VB ein Module kennt,
    was einen anderen (hier widersprechenden) Hintergrund hat.

    Gruß Elmar

    Donnerstag, 9. Dezember 2010 13:10
    Beantworter
  • Vielen Dank erstmal.

    Das wird trotz allem glaube ich recht kompliziert.

    Die Klassennamen habe ich mir akut ausgedacht um das Problem etwas transparenter zumachen.

    in der Realität sind die Namen nämlich überhaupt nicht transparent (und bedürfen eigentlich der Änderung)

     

    Donnerstag, 9. Dezember 2010 13:34
  • Hallo Nico,

    so "kompliziert" ist das nicht, wenn man das Ganze vom Konzept erst einmal verstanden hat.

    Wenn Du Probleme mit dem "Einbau" in Deine reale Umgebung hat, frage nach!

    Gruß Elmar

    Freitag, 10. Dezember 2010 13:50
    Beantworter