none
Shared Event Handler RRS feed

  • Frage

  • Liebe Community,

    wieder ein kleiner theorethischer Stolperstein:

    Friend NotInheritable Class TestGeneralVB_3
        Private Shared Event MySharedPrivateEvent()
    
        Private Sub HandlerOf_MySharedPrivateEvent() Handles MyClass.MySharedPrivateEvent
            ' Do nothing
        End Sub
    End Class
    wird ohne Compiler-Warnung akzeptiert. Die folgende leicht abgewandelte Klasse:

    Friend NotInheritable Class TestGeneralVB_3
        Private Shared Event MySharedPrivateEvent()
    
        Private Sub HandlerOf_MySharedPrivaedEvent() Handles MyClass.MySharedPrivateEvent
            ' Do nothing
        End Sub
    
        Public Sub New()
            ' Do nothing
        End Sub
    End Class
    mit einem Konstruktor hingegen wird mit der Warnung: "Zugriff des freigegebenen Members, konstanten Members, Enumerationsmembers oder geschachtelten Typs über eine Instanz; der qualifizierende Ausdruck wird nicht ausgewertet." quittiert.

    Beide Klassen machen (auch im kompilierten Zustand) exakt das was sie sollen, aber warum kommt es zu dieser Warnung? (Interessanterweise an Stelle: Zeile 1, Spalte 1 - also beim 'F'.)

    Die Warnug verschwindet (erwartungsgemäß) wenn folgende Änderung vorgenommen wird:

    Friend NotInheritable Class TestGeneralVB_3
        Private Shared Event MySharedPrivateEvent()
    
        Private Sub HandlerOf_MySharedPrivateEvent() ' Handles MyClass.MySharedPrivateEvent
            ' Do nothing
        End Sub
    
        Public Sub New()
            AddHandler MySharedPrivateEvent, AddressOf HandlerOf_MySharedPrivateEvent
        End Sub
    End Class
    Mein Problem ist also eigentlich gelöst. Vom Verständnis (und der Logik) ist die 2. Variante die Beste, nur würde ich gerne den Kompilerfehler wegbekommen. Gibt es da eine Möglichkeit?

    Beste Grüße.
    Sonntag, 3. Januar 2010 13:56

Antworten

  • Hallo,

    MyClass oder auch Me bezieht sich immer auf die aktuelle Instanz der Klasse. Statische Member gehören aber nicht zur Instanz der Klasse, daher weist Dich der Compiler darauf hin, dass Dein Ausdruck nicht so, wie Du es eventuell in der Absicht haben könntest, umsetzen wird. Im Grunde heißt es nur, dass er das Schlüsselwort "Me" oder "MyClass" ignoriert.

    Wenn Du es mit AddHandler so schreibst, wie bei der Handles Anweisung, bekommst Du die gleiche Fehlermeldung, nur diesmal mit der passenden Zeilen- und Spaltennummer:

      Public Sub New()
        AddHandler MyClass.MySharedPrivateEvent, AddressOf HandlerOf_MySharedPrivaedEvent
      End Sub

    Warum bekommst Du diese jetzt nicht bei der Handles Anweisung? Weil VB hier wieder im Hintergrund Code zusammenbaut und im Grunde eine AddHandler Anweisung im kompilierten Code erzeugt. Dieser automatisch generierte Code erzeugt die Compiler Warnung, kann aber der Codedatei nicht zugeordnet werden. Daher Zeilen- und Spaltennummer 1.

    Korrekt müsste die Deklaration der Handles Anweisung, wie folgt sein:

      Private Sub HandlerOf_MySharedPrivaedEvent() Handles TestGeneralVB_3.MySharedPrivateEvent
        ' Do nothing
      End Sub

    Das funktioniert aber nicht, da VB hier eine mit WithEvents deklarierte Variable "TestGeneralVB_3" erwartet. Führt aber nicht zum gewünschten Ergebnis. Also sollte man meinen, man lässt "TestGeneralVB_3" einfach weg, um sich auf das statische Event zu beziehen. Schlägt aber auch fehl, da VB einen voll qualifizierten Ausdruck erwartet. Also bleibt als sauberer Weg nur AddHandler übrig:

      Public Sub New()
        AddHandler TestGeneralVB_3.MySharedPrivateEvent, AddressOf HandlerOf_MySharedPrivaedEvent
      End Sub

    Wäre das Event in einer separaten Klasse deklariert, käme man jetzt auch nicht in Versuchung Instanz- und statische Member zu vermischen und das Handles Schlüsselwort zu verwenden, was ja im Normalfall mit statischen Events ohnehin nicht möglich ist. Hier muss man ja auch über die AddHandler Anweisung arbeiten.

    Anbei noch ein Beispiel, wie man das statische Event auslagern könnte, um den Code selbstdokumentierend zu gestalten:

    Friend NotInheritable Class TestGeneralVB_3
    
      Private Sub HandlerOf_MySharedPrivaedEvent()
        ' Do nothing
      End Sub
    
      Public Sub New()
        AddHandler SharedEventNotifier.MySharedPrivateEvent, AddressOf HandlerOf_MySharedPrivaedEvent
      End Sub
    
      Public Sub RaiseSharedEvent()
        SharedEventNotifier.OnSharedPrivateEvent()
      End Sub
    
      Private Class SharedEventNotifier
        Public Shared Event MySharedPrivateEvent()
    
        Public Shared Sub OnSharedPrivateEvent()
          RaiseEvent MySharedPrivateEvent()
        End Sub
      End Class
    
    End Class

    Das muss man nicht so machen, aber ich denke dadurch wird das Zusammenspiel und die gewünschte Funktionsweise besser verständlich.

    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Sonntag, 3. Januar 2010 15:04
    Moderator
  • Hallo,

    ergänzend zu Thorstens Antwort:

    Visual Basic erstellt bei Handles erzeugt im Hintergrund den Code für den Konstruktor.
    Wenn Du ohnehin statisches (shared) Ereignis hast, so sollte das i. a. auf eine statische Adresse zeigen,
    was im shared Konstruktor abgewickelt würde.

    Friend NotInheritable Class TestGeneralVB_3
        Private Shared Event AnotherSharedPrivateEvent()
    
        ' Für manuellen Handler für vollständige VB Kompatibilität mit Synchronized-Attribut
        '<System.Runtime.CompilerServices.MethodImpl(Runtime.CompilerServices.MethodImplOptions.Synchronized)> _
        Private Shared Sub HandlerOf_AnotherSharedPrivateEvent() Handles MyClass.AnotherSharedPrivateEvent
            ' Einer für alle
        End Sub
    
        ' Handles entspricht (+ MethodImpl)
        'Shared Sub New()
        '    AddHandler TestGeneralVB_3.MySharedPrivateEvent, AddressOf TestGeneralVB_3.HandlerOf_AnotherSharedPrivateEvent
        'End Sub
    End Class
    
    Gruß Elmar




    Sonntag, 3. Januar 2010 20:24
    Beantworter

Alle Antworten

  • Hallo,

    MyClass oder auch Me bezieht sich immer auf die aktuelle Instanz der Klasse. Statische Member gehören aber nicht zur Instanz der Klasse, daher weist Dich der Compiler darauf hin, dass Dein Ausdruck nicht so, wie Du es eventuell in der Absicht haben könntest, umsetzen wird. Im Grunde heißt es nur, dass er das Schlüsselwort "Me" oder "MyClass" ignoriert.

    Wenn Du es mit AddHandler so schreibst, wie bei der Handles Anweisung, bekommst Du die gleiche Fehlermeldung, nur diesmal mit der passenden Zeilen- und Spaltennummer:

      Public Sub New()
        AddHandler MyClass.MySharedPrivateEvent, AddressOf HandlerOf_MySharedPrivaedEvent
      End Sub

    Warum bekommst Du diese jetzt nicht bei der Handles Anweisung? Weil VB hier wieder im Hintergrund Code zusammenbaut und im Grunde eine AddHandler Anweisung im kompilierten Code erzeugt. Dieser automatisch generierte Code erzeugt die Compiler Warnung, kann aber der Codedatei nicht zugeordnet werden. Daher Zeilen- und Spaltennummer 1.

    Korrekt müsste die Deklaration der Handles Anweisung, wie folgt sein:

      Private Sub HandlerOf_MySharedPrivaedEvent() Handles TestGeneralVB_3.MySharedPrivateEvent
        ' Do nothing
      End Sub

    Das funktioniert aber nicht, da VB hier eine mit WithEvents deklarierte Variable "TestGeneralVB_3" erwartet. Führt aber nicht zum gewünschten Ergebnis. Also sollte man meinen, man lässt "TestGeneralVB_3" einfach weg, um sich auf das statische Event zu beziehen. Schlägt aber auch fehl, da VB einen voll qualifizierten Ausdruck erwartet. Also bleibt als sauberer Weg nur AddHandler übrig:

      Public Sub New()
        AddHandler TestGeneralVB_3.MySharedPrivateEvent, AddressOf HandlerOf_MySharedPrivaedEvent
      End Sub

    Wäre das Event in einer separaten Klasse deklariert, käme man jetzt auch nicht in Versuchung Instanz- und statische Member zu vermischen und das Handles Schlüsselwort zu verwenden, was ja im Normalfall mit statischen Events ohnehin nicht möglich ist. Hier muss man ja auch über die AddHandler Anweisung arbeiten.

    Anbei noch ein Beispiel, wie man das statische Event auslagern könnte, um den Code selbstdokumentierend zu gestalten:

    Friend NotInheritable Class TestGeneralVB_3
    
      Private Sub HandlerOf_MySharedPrivaedEvent()
        ' Do nothing
      End Sub
    
      Public Sub New()
        AddHandler SharedEventNotifier.MySharedPrivateEvent, AddressOf HandlerOf_MySharedPrivaedEvent
      End Sub
    
      Public Sub RaiseSharedEvent()
        SharedEventNotifier.OnSharedPrivateEvent()
      End Sub
    
      Private Class SharedEventNotifier
        Public Shared Event MySharedPrivateEvent()
    
        Public Shared Sub OnSharedPrivateEvent()
          RaiseEvent MySharedPrivateEvent()
        End Sub
      End Class
    
    End Class

    Das muss man nicht so machen, aber ich denke dadurch wird das Zusammenspiel und die gewünschte Funktionsweise besser verständlich.

    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Sonntag, 3. Januar 2010 15:04
    Moderator
  • Hallo,

    ergänzend zu Thorstens Antwort:

    Visual Basic erstellt bei Handles erzeugt im Hintergrund den Code für den Konstruktor.
    Wenn Du ohnehin statisches (shared) Ereignis hast, so sollte das i. a. auf eine statische Adresse zeigen,
    was im shared Konstruktor abgewickelt würde.

    Friend NotInheritable Class TestGeneralVB_3
        Private Shared Event AnotherSharedPrivateEvent()
    
        ' Für manuellen Handler für vollständige VB Kompatibilität mit Synchronized-Attribut
        '<System.Runtime.CompilerServices.MethodImpl(Runtime.CompilerServices.MethodImplOptions.Synchronized)> _
        Private Shared Sub HandlerOf_AnotherSharedPrivateEvent() Handles MyClass.AnotherSharedPrivateEvent
            ' Einer für alle
        End Sub
    
        ' Handles entspricht (+ MethodImpl)
        'Shared Sub New()
        '    AddHandler TestGeneralVB_3.MySharedPrivateEvent, AddressOf TestGeneralVB_3.HandlerOf_AnotherSharedPrivateEvent
        'End Sub
    End Class
    
    Gruß Elmar




    Sonntag, 3. Januar 2010 20:24
    Beantworter
  • Hallo RiverSpoon,

    Ich gehe davon aus, dass die Antworten Dir weitergeholfen haben.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert

    Mittwoch, 13. Januar 2010 12:07
    Moderator