Benutzer mit den meisten Antworten
Daten an mehrere Instanzen einer Klasse weitergeben

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
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
- Als Antwort markiert Robert BreitenhoferModerator Freitag, 10. Dezember 2010 09:37
-
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
Microsoft MVP Office Access
https://mvp.support.microsoft.com/profile/Stefan.Hoffmann- Als Antwort markiert Robert BreitenhoferModerator Freitag, 10. Dezember 2010 09:37
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
Microsoft MVP Office Access
https://mvp.support.microsoft.com/profile/Stefan.Hoffmann- Als Antwort markiert Robert BreitenhoferModerator Freitag, 10. Dezember 2010 09:37
-
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
- Als Antwort markiert Robert BreitenhoferModerator Freitag, 10. Dezember 2010 09:37
-
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)