2016-05-14 27 views
1

Angesichts zwei Klassen mit identischen Ereignissen möchte ich in der Lage sein, mit einem Namen auf sie verweisen. Ähnlich wie die folgenden:Wie verknüpfe ich verschiedene Klassen mit denselben Ereignissen zur Laufzeit?

Public Class myclass1 
    Public event1() 
End Class 

Public Class myclass2 
    Public event1() 
End Class 

Hier würde Ich mag während der Laufzeit die Klasse zu bestimmen, in der Lage sein zu verwenden:

Sub somefunction(select as integer) 
    Dim voidclass 
    if select = 1 then 
     voidclass = myclass1 
    else 
     voidclass = myclass2 
    end if 
    AddHandler voidclass.event1, AddressOf eventhappened 
End Sub 

Sub eventhappened() 
    msgbox("Event occured") 
End Sub 

Offensichtlich kann es eine bessere Methode für dieses Beispiel sein, aber lasst uns gehe davon aus, dass die Klasse book1 bereits existiert und dass ich die Aufgabe habe, book2 zu erstellen und nur somefunction zu modifizieren, ohne book1 selbst zu ändern.

Das obige Beispiel sollte zu dem Fehler event1 führen, ist kein Ereignis von 'Object'.

Es scheint, dass Eigenschaften und Methoden in Ordnung sind, aber Ereignisse nicht. Wie gehe ich in dieser Situation mit Ereignissen um?

+0

Was ist mit Gießen kombiniert mit 'GetType()' Vergleich? Oder erstellen Sie eine Basisklasse, von der die anderen Klassen abgeleitet sind, wobei die Basisklasse das Ereignis enthält. Dann können Sie einfach in die Basisklasse umwandeln. –

Antwort

1

Sie können eine Schnittstelle für das Ereignis definieren und in den Klassen implementieren, dann können Sie dieses Ereignis über die Schnittstellenreferenz abonnieren. Siehe unten:

Public Interface INotifier 
    Event SomethingHappened() 
End Interface 

Public Class Class1 
    Implements INotifier 

    Public Event SomethingHappened() Implements INotifier.SomethingHappened 
End Class 

Public Class Class2 
    Implements INotifier 

    Public Event SomethingHappened() Implements INotifier.SomethingHappened 
End Class 

Module Module1 

    Dim notifiers As List(Of INotifier) = New List(Of INotifier) From 
    { 
     New Class1(), 
     New Class2() 
    } 

    Sub Main() 
     SubscribeToEventHandler(0) 
    End Sub 

    Private Sub SubscribeToEventHandler(ByVal index As Integer) 
     Dim notifier As INotifier = notifiers(index) 
     AddHandler notifier.SomethingHappened, AddressOf EventHandler 
    End Sub 

    Private Sub EventHandler() 

    End Sub 

End Module 
2

Das Snippet passt nicht sehr gut zur Frage. Es hat einen seltsamen Fehler, die Ereignisse in den Klassen sind nicht Shared deklariert, so dass der Code eine ordnungsgemäße Objektreferenz verwenden muss. Kein Typname. Vielleicht ist die Antwort so einfach wie:

Private obj1 As myclass1 
    Private obj2 As myclass2 

    Sub somefunction(select as integer) 
     If select = 1 Then 
      AddHandler obj1.event1, AddressOf eventhappened 
     Else 
      AddHandler obj2.event1, AddressOf eventhappened 
     End If 
    End Sub 

Aber vermutlich die eigentliche Frage ist das gleiche Szenario, aber jetzt sind die Variablen deklariert als:

Private obj1, obj2 

Untypisierte und damit Object. Ja, VB.NET unterstützt das nicht. Wie bei den meisten Macken in VB.NET gibt es Geschichte dahinter. VB unterstützte niemals die explizite späte Bindung von Ereignissen, nur Methoden und Eigenschaften. Das Schema in den alten Versionen war sehr eigenartig. Sie mussten die Variable mit dem Schlüsselwort WithEvents deklarieren und einen spezifischen Namen für den Event-Handler auswählen. Mit anderen Worten:

Dim WithEvents obj1 

    Sub obj1_somethinghappened 
     '' handles the event1 event for obj1 
    End Sub 

Oder um es anders auszudrücken, alle Ereignisse waren spät gebunden. Dieses Schema wurde nicht in VB.NET übernommen, zu viele praktische Probleme damit. WithEvents überlebt weiterhin, erfordert jetzt jedoch das Schlüsselwort Handles in der Methodendeklaration. Das macht nicht, was du willst.

Die VB.NET-Designer hinzugefügt absichtlich keine späte Bindung Unterstützung der AddHandler-Anweisung. Ich weiß nicht genau, warum sie das entschieden haben und können nur raten. Es gibt keinen technischen Grund, warum es nicht hinzugefügt werden könnte, es erfordert lediglich, dass der Compiler einen Reflexionscode generiert. Eine mögliche Erklärung ist, dass sie es für zu teuer hielten. Ein anderes ist, dass sie die Laufzeitausnahmen betrachteten, die ausgelöst werden, wenn ein Methodensignatur-Mismatch zu schwer zu interpretieren ist. Ich mag das letzte am besten, sie sind furchtbar hässlich.

Sie müssen Reflection verwenden, um zu bekommen, was Sie wollen. Verwenden Sie obj1.GetType(). GetEvent ("event1"), um die EventInfo abzurufen, und Get/AddMethod(), um den Ereignishandler hinzuzufügen.

Fwiw, die C# -Sprache unterstützt dies in seiner dynamischen Schlüsselwort-Implementierung. Vielleicht können Sie einen Bug in ihr Ohr von asking for the feature setzen.Keine echte Idee, wenn dies vorher beantragt wurde.